home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
grafik
/
bildanzeiger
/
seepix
/
source.lha
/
FS.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-27
|
79KB
|
3,448 lines
/**FS.c******************************************************************
* *
* SeePix -- by Hank Schafer *
* *
* SeePix is an IFF Picture Viewer. It works with Lo-Res, *
* Med-Res, Hi-Res, HAM, and EHB formats. I'm working on support *
* for X-Specs, and Anim5 formats. *
* *
* SeePix is based on a program by Olaf Barthel, called *
* 'LoadImage'. As released, LoadImage had a couple of bugs. *
* The Amiga-Key alternatives to menu use didn't all work. That's *
* been fixed. There were two separate print functions in LoadImage *
* which behaved exactly the same. The redundancy was eliminated. *
* LoadImage used the Topaz ROMFONT, and made no allowances for a *
* different system default font (under 2.04). I added a built-in *
* font. I've reworked the code considerably from the original *
* release, to allow for optimizations based on time and space. *
* *
* SeePix features a palette tool which allows "tweaking" of colors *
* prior to printing, allowing you to modify the color printout to *
* more closely resemble the original graphics (Blue is Blue, not *
* Purple). SeePix can be Iconified. SeePix features an ARP *
* interface. SeePix now uses the PathMaster File Selector. *
* *
************************************************************************
* *
* SeePix Copyright © 1992 by Hank Schafer; all rights reserved. *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation, either version 1, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to: *
* Free Software Foundation, Inc. *
* 675 Massachusetts Ave. *
* Cambridge MA 02139, USA *
* *
**************** Special Function Copyright Notices ********************
* *
****LoadImage Copyright Notice: *
* *
* LoadImage is © Copyright 1988, 1989, 1990 by MXM, all rights *
* reserved, written by Olaf Barthel. No guarantees of any kind are *
* made that this program is 100% reliable. Use this program on *
* your own risk! *
* *
****Iconify Copyright Notice: *
* *
* Copyright 1987 by Leo L. Schwab. *
* Permission is hereby granted for use in any and all programs, *
* both Public Domain and commercial in nature, provided this *
* Copyright notice is left intact. *
* *
****ColorWindow (Palette) Copyright Notice: *
* *
* ColorWindow Routine -- Color Window Routines *
* from Book 1 of the Amiga Programmers' Suite by RJ Mical *
* *
* Copyright (C) 1986, 1987, Robert J. Mical *
* All Rights Reserved. *
* *
****PathMaster Copyright Notice: *
* *
* -------------------------------------------------------------------- *
* Copyright © 1989 Justin V. McCormick. All Rights Reserved. *
* -------------------------------------------------------------------- *
* *
* The PathMaster name is a trademark of Justin V. McCormick. *
* *
* PathMaster File Selector source and documentation written by: *
* *
* Justin V. McCormick. *
* Copyright © 1989 by Justin V. McCormick. *
* All Rights Reserved. *
* *
* -------------------------------------------------------------------- *
************************************************************************
* *
* Hope this is something you can use and enjoy. *
* *
************************************************************************/
#include "Config.h"
#ifdef PATHMASTER
#asm
INCLUDE "Exec/Types.i"
INCLUDE "Exec/Nodes.i"
INCLUDE "Exec/Lists.i"
SYS MACRO *
IFGT NARG-2
FAIL !!!
ENDC
IFEQ NARG-2
MOVE.L \2,a6
ENDC
JSR _LVO\1(a6)
ENDM
XLVO MACRO *
XREF _LVO\1
ENDM
; These three equate control the size of the path, file, and
; pattern string limits
PATHSTRSIZE EQU 300
FILESTRSIZE EQU 32
MATCHSTRSIZE EQU 32
AUTOKNOB EQU $1
FREEVERT EQU $4
PROPBORDERLESS EQU $8
MEMF_CLEAR EQU $10000
WINDOWSIZING EQU $1
WINDOWDRAG EQU $2
WINDOWDEPTH EQU $4
WINDOWCLOSE EQU $8
WINDOWTGADS EQU WINDOWDRAG!WINDOWDEPTH!WINDOWCLOSE
FPEN EQU 1
DPEN EQU 3
fib_DirEntryType EQU $4
fib_FileName EQU $8
fib_Size EQU $7C
fib_DateStamp EQU $84
fib_SIZEOF EQU $104
gg_Flags EQU $C
id_SIZEOF EQU $24
it_FrontPen EQU $0
it_IText EQU $C
rp_AreaPtrn EQU $8
rp_AreaPtSz EQU $1D
wd_Flags EQU $18
wd_RPort EQU $32
STRUCTURE FSRequest,0
STRUCT fs_dirname,PATHSTRSIZE
STRUCT fs_filename,FILESTRSIZE
STRUCT fs_matchpattern,MATCHSTRSIZE
WORD fs_leftedge
WORD fs_topedge
WORD fs_sorttype
UWORD fs_flags
ULONG fs_windowflags
CPTR fs_fullname
CPTR fs_ignorepattern
CPTR fs_pathgadstr
CPTR fs_filegadstr
CPTR fs_titlestr
CPTR fs_readingstr
CPTR fs_sortingstr
CPTR fs_emptydirstr
CPTR fs_nomatchstr
CPTR fs_selectfilestr
CPTR fs_selectstr
CPTR fs_cancelstr
CPTR fs_specgadstr
CPTR fs_userscreen
CPTR fs_userport
CPTR fs_specgadfunc
CPTR fs_dirfunc
CPTR fs_filefunc
CPTR fs_userfunc
CPTR fs_initfunc
CPTR fs_matchfunc
LABEL fs_SIZEOF
STRUCTURE node_data,0
STRUCT nd_alphadata,58
WORD nd_filetype
WORD nd_showit
WORD nd_textcolor
WORD nd_namelength
ULONG nd_filesize
ULONG nd_days
ULONG nd_minutes
ULONG nd_ticks
LABEL nd_SIZEOF
STRUCTURE file_node,0
STRUCT fn_Node,MLN_SIZE
CPTR fn_info
WORD fn_idnum
LABEL fn_SIZEOF
STRUCTURE dev_node,0
STRUCT dn_Node,MLN_SIZE
STRUCT dn_name,32
LABEL dn_SIZEOF
XREF _AlphaGad
XREF _ColonStr
XREF _CurDevNames
XREF _DevGads
XREF _devList
XREF _DevTxts
XREF _DOSBase
XREF _EmptyPattern
XREF _FileUndoBuffer
XREF _FileUndoName
XREF _fnList
XREF _fsbaddatestr
XREF _FSCountDown
XREF _fscurmicros
XREF _fscursecs
XREF _fsdatefmtstr
XREF _fsdayspermonth
XREF _FSDirFmtStr
XREF _fsdirlocked
XREF _FSDone
XREF _FSDownGad
XREF _fserrmsgs
XREF _FSFib
XREF _FSFileGad
XREF _FSFileInfo
XREF _FSFileNodes
XREF _fsflags
XREF _FSIgnorePat
XREF _FSInfo
XREF _FSLock
XREF _fsneedshow
XREF _FSNextDevs
XREF _fsnumentries
XREF _fsoldmicros
XREF _fsoldsecs
XREF _FSPathBuf
XREF _FSPathGad
XREF _FSPathInfo
XREF _FSPatternGad
XREF _FSPatternInfo
XREF _FSPatternUndoBuffer
XREF _FSPrevDevs
XREF _fsprevgadid
XREF _FSReq
XREF _FSRPort
XREF _FSSizeFmtStr
XREF _FSSlideGad
XREF _FSSlideProp
XREF _fsstartedstr
XREF _fstempdate
XREF _fstitlelength
XREF _fstitstatus
XREF _FSUndoGad
XREF _FSUpGad
XREF _FSUserGad
XREF _fsvheight
XREF _fsvirgindir
XREF _fsvposition
XREF _FSWin
XREF _FSWinTitleStr
XREF _FSwstr
XREF _GfxBase
XREF _IntuitionBase
XREF _lastdev
XREF _NIL2Gad
XREF _OldFSPathBuf
XREF _RamDirNameStr
XREF _SizeGad
XREF _SlashStr
XREF _TimeGad
XREF _topfin
XREF _sprintf
XREF _FSVBDelay
IFD BENCHMARK
XREF _StartTime
XREF _StopTime
XREF _timermsg1
ENDC
XLVO ActivateGadget
XLVO AddHead
XLVO AddTail
XLVO AllocMem
XLVO ClipBlit
XLVO DisplayBeep
XLVO DoubleClick
XLVO Examine
XLVO ExNext
XLVO FreeMem
XLVO GetMsg
XLVO Insert
XLVO IoErr
XLVO Move
XLVO NewModifyProp
XLVO ParentDir
XLVO RectFill
XLVO RefreshGList
XLVO RemHead
XLVO ReplyMsg
XLVO SetAPen
XLVO SetDrMd
XLVO SetWindowTitles
XLVO Text
XLVO UnLock
SECTION CODE
; LONG MyActivateGad(gadget, window)
; struct Gadget *gadget;
; struct Window *window;
;
; Activate a gadget, wait till it is ready. Try up to 3 times. Returns
; TRUE (1) if it succeeded, FALSE (0) if it failed to activate.
XDEF _MyActivateGad
_MyActivateGad:
movem.l d2/a2/a6,-(sp)
moveq #2,d2 ;Try 3 times to activate gadget
1$ movem.l 16(sp),a0/a1 ;Grab gadget pointer, window pointer
suba.l a2,a2 ;No requester pointer
movea.l _IntuitionBase,a6
jsr _LVOActivateGadget(a6) ;Activate!
tst.l d0 ;Did it catch?
bne.s 2$ ;Yep, move on
pea 5
jsr _FSVBDelay
addq.w #4,sp
dbf d2,1$
2$
movem.l (sp)+,d2/a2/a6
rts
; LONG FSCheckFlagChange(VOID);
XDEF _FSCheckFlagChange
_FSCheckFlagChange:
movea.l _FSReq,a0
move.w fs_flags(a0),d0
move.w _fsflags,d1
andi.w #%00011000,d0
andi.w #%00011000,d1
cmp.w d0,d1 ;FS_SHOW_FILES_FIRST or FS_SHOW_DIRS_FIRST changed?
beq.s 1$ ;Nope
move.w #1,_fsvirgindir ;Else we need to re-read the directory
1$
move.w fs_flags(a0),d0
move.w _fsflags,d1
andi.w #%01100000,d0
andi.w #%01100000,d1
cmp.w d0,d1 ;FS_SHOW_FILES_ONLY or FS_SHOW_DIRS_ONLY changed?
beq.s 2$ ;Nope
moveq #1,d0 ;Else flag that we need to FSMatchPattern()
bra.s 3$
2$
moveq #0,d0
3$
move.w fs_flags(a0),_fsflags ;Reset flags to match FSReq now
rts
; Assign device name texts to intuitexts in the 4 Device Gadgets
XDEF _SetDevGads
_SetDevGads:
movem.l d3-d4/a2-a3/a5,-(sp)
;for (i = 0, tnode = lastdev; i < 4;)
moveq #0,d4 ;d4 = i = 0
movea.l _lastdev,a2 ;a2 = tnode = lastdev
move.l a2,d3 ;Copy for comparison
lea _CurDevNames,a3 ;a3 = &CurDevNames[0]
lea _DevTxts,a5 ;a5 = &DevTxts[0]
1$
lea dn_name(a2),a1
move.l a1,0(a3,d4.w) ;CurDevNames[i] = tnode->name
moveq #4,d0
move.l 0(a5,d4.w),a0
movea.l it_IText(a0),a0
jsr astrncpy ;astrncpy (DevTxts[i]->IText, tnode->name, 4)
addq.w #4,d4 ;i++
movea.l dn_Node+MLN_SUCC(a2),a2 ;tnode = tnode->dn_Node.mln_Succ
tst.l dn_Node+MLN_SUCC(a2) ;if (tnode->dn_Node.mln_Succ == 0)
bne.s 2$ ;Nope
movea.l _devList,a2
movea.l MLH_HEAD(a2),a2 ;Else start the listing over at the start
2$
cmpa.l d3,a2 ;Have we already shown this node?
beq.s 3$ ;Yep, disable the rest
cmpi.w #16,d4 ;Set all 4 Device gadgets yet?
bcs 1$ ;Nope, do next
3$
; Disable any leftover gadgets
;for (; i < 4; i++)
lea _DevGads,a0
bra.s 5$
4$ movea.l 0(a0,d4.w),a1
bset.b #0,gg_Flags(a1) ;DevGads[i]->Flags |= GADGDISABLED
addq.w #4,d4
5$ cmpi.w #16,d4
bcs 4$
movem.l (sp)+,d3-d4/a2-a3/a5
rts
; FSScrollDevGads(direction)
; WORD direction;
XDEF _FSScrollDevGads
_FSScrollDevGads:
movem.l a2/a6,-(sp)
movea.l _lastdev,a0
tst.w 12+2(sp) ;Grab scroll direction
beq.s 1$ ;If zero, scroll to next
; Bump list pointer one direction or the other
move.l dn_Node+MLN_SUCC(a0),a0 ;Get successor
tst.l dn_Node+MLN_SUCC(a0) ;EndoList?
bne.s 2$ ;Nope
movea.l _devList,a0
movea.l MLH_HEAD(a0),a0 ;Else lastdev = devList->lh_Head
bra.s 2$
1$
movea.l dn_Node+MLN_PRED(a0),a0 ;Else, lastdev = lastdev->next
tst.l dn_Node+MLN_PRED(a0) ;Endolist?
bne.s 2$
movea.l _devList,a0
movea.l MLH_TAILPRED(a0),a0 ;Else lastdev = devList->lh_TailPred
2$
move.l a0,_lastdev
jsr _SetDevGads ;Set the gadget text fields
; Refresh gadget texts
; RefreshGList(&NIL2Gad, FSWin, 0L, 4L);
moveq #4,d0
suba.l a2,a2
movea.l _FSWin,a1
lea _NIL2Gad,a0
SYS RefreshGList,_IntuitionBase
movem.l (sp)+,a2/a6
rts
; CheckFSArrows()
; See if the Up or Down arrow gadgets are currently activated, scroll
; the file display area or device gadget list if so.
XDEF _CheckFSArrows
_CheckFSArrows:
subq.w #1,_FSCountDown
bge.s 12$
btst.b #7,_FSUpGad+gg_Flags+1 ;FSUpGad.Flags & SELECTED?
beq.s 2$ ;Nope, maybe FSDownGad
pea 1 ;Otherwise scroll filegadgets up
bra.s 3$
2$ btst.b #7,_FSDownGad+gg_Flags+1 ;FSDownGad.Flags & SELECTED?
beq.s 4$ ;Nope, maybe slide gadget is selected
pea 0 ;Otherwise scroll filegadgets down
3$ jsr _FSScrollFileGads
addq.w #4,sp
move.w #0,_FSCountDown ;Set timer to wake up in .02 secs.
bra.s 12$
4$ btst.b #7,_FSSlideGad+gg_Flags+1 ;FSSlideGad.Flags & SELECTED?
beq.s 5$ ;Nope, maybe UpDev
jsr _FSDoSlideGadget ;Process slide gadget motion
move.w #0,_FSCountDown ;Set timer to wake up in .02 secs.
bra.s 12$
5$ btst.b #7,_FSPrevDevs+gg_Flags+1 ;FSPrevDevs.Flags & SELECTED?
beq.s 7$ ;Nope, maybe DownDev
pea 1 ;Otherwise FSScrollDevGads(1);
6$ jsr _FSScrollDevGads
addq.w #4,sp
move.w #1,_FSCountDown ;Set timer to wake up in .16 secs.
bra.s 12$
7$ btst.b #7,_FSNextDevs+gg_Flags+1 ;FSNextDevs.Flags & SELECTED?
beq.s 10$ ;Nope, nothing of interest, slow down
pea 0 ;Else FSScrollDevGads(0);
bra 6$
10$
move.w #4,_FSCountDown
12$
rts
; BYTE *FibFileDate(fib_date)
; struct DateStamp *fib_date;
;
; Calculate date based on DateStamp structure and return a pointer
; to the formatted date text.
XDEF _FibFileDate
_FibFileDate:
link a5,#0
movem.l d3-d7,-(sp)
movea.l 8(a5),a1 ;Grab datestamp pointer
moveq #78,d7 ;Initial year = 1978
move.l (a1),d5 ;days = fib_date->ds_Days
blt ffdbaddate ;Hey! you can't be negative! Invalid date...
; Determine what year it is
divu #1461,d5
move.l d5,d0 ;Stash it
ext.l d5
lsl.l #2,d5
add.l d5,d7 ;year += (days / 1461) * 4
; Count how many months into that year
ffdgetmo:
swap d0
moveq #0,d5
move.w d0,d5 ;days %= 1461
1$ tst.w d5 ;Out of days yet?
beq.s 3$ ;Yep, done here
move.w #365,d6 ;Else month_days = 365
move.w d7,d0 ;Grab year
andi.w #3,d0 ;if (year & 3) == 0 Leap year?
bne.s 2$ ;Nope
addq.w #1,d6 ;Otherwise bump month_days
2$ cmp.w d6,d5 ;is day < month_days?
bcs.s 3$ ;yep, done here
sub.w d6,d5 ;otherwise day -= month_days
addq.l #1,d7 ; year++
bra 1$
3$
; Count how many days into that month of that year
ffdgetday:
; for (i = 0, day++; i < 12; i++)
moveq #0,d4 ;current month = 0
moveq #0,d6 ;Zap hinybs
addq.w #1,d5
lea _fsdayspermonth,a0
1$ move.b 0(a0,d4.w),d6 ;month_days = _fsdayspermonth[i]
cmpi.w #1,d4 ;if (i == 1 && (year & 3) == 0)
bne.s 2$
move.w d7,d0
andi.w #3,d0
bne.s 2$
addq.w #1,d6 ;month_days++
2$ cmp.w d6,d5 ;if (day <= month_days)
ble.s 4$ ;Break out, found the right month
sub.w d6,d5 ;Else, day -= month_days
addq.w #1,d4 ;i++
3$ cmpi.w #12,d4 ;Done all months yet?
bcs 1$ ;Nope
4$
ffdprint:
1$ cmpi.l #99,d7 ;while (year >= 100)
ble.s 2$
subi.l #100,d7 ;year -= 100
bra 1$
2$
;sprintf(_fstempdate, "%02ld-%02ld-%02ld %02ld:%02ld:%02ld", year, i + 1, day, hour, min, sec)
move.l 8(a1),d0 ;sec = fib_date->ds_Tick / 50;
divu.w #50,d0
ext.l d0
move.l d0,-(sp) ;Push secs
moveq #0,d0 ;Zap reg
move.w 6(a1),d0 ;min = fib_date->ds_Minute
move.w d0,d1 ;Clone it
divu #60,d0
move.w d0,d3 ;hour = min / 60
ext.l d3
mulu #60,d0
sub.w d0,d1 ;min -= hour * 60
ext.l d1
move.l d1,-(sp) ;Push mins
move.l d3,-(sp) ;Push hours
move.l d5,-(sp) ;Push day of month
addq.w #1,d4 ;Push month (offset by 1!)
move.l d4,-(sp)
move.l d7,-(sp) ;Push year
pea _fsdatefmtstr ;Push the format pattern
pea _fstempdate ;Push destination buffer
jsr _sprintf
lea 32(sp),sp
lea _fstempdate,a0
move.l a0,d0 ;return((BYTE *)&_fstempdate[0])
ffddone:
movem.l (sp)+,d3-d7
unlk a5
rts
ffdbaddate:
lea _fsbaddatestr,a0
move.l a0,d0 ;return (" <Invalid Date> ")
bra ffddone
XDEF _FSSetKnobHeight
_FSSetKnobHeight:
; vheight = (ULONG)( 655350L / (long)fsnumentries );
move.w _fsnumentries,d1
cmpi.w #10,d1
bhi.s 1$
move.w #$ffff,_fsvheight
rts
1$
move.l #655350,d0
divu d1,d0
move.w d0,_fsvheight
3$
rts
XDEF _FSSetKnobPos
_FSSetKnobPos:
movea.l _topfin,a0
moveq #0,d0
move.w fn_idnum(a0),d0
swap d0
move.w _fsnumentries,d1
subi.w #10,d1
bhi.s 1$
moveq #0,d0
bra.s 2$
1$
divu d1,d0
bvc.s 2$
move.w #$ffff,d0
2$
move.w d0,_fsvposition
rts
XDEF _FSResetKnob
_FSResetKnob:
jsr _FSSetKnobHeight
jsr _FSSetKnob
rts
; FSSetKnob()
; Call ModifyProp() to actually update slide image in window.
XDEF _FSSetKnob
_FSSetKnob:
movem.l d2-d5/a2/a6,-(sp)
; NewModifyProp(&FSSlideGad, FSWin, 0L, AUTOKNOB|FREEVERT|PROPB, 0L, vposition, 0xffffL, vheight, 1L)
lea _FSSlideGad,a0
movea.l _FSWin,a1
suba.l a2,a2
moveq #AUTOKNOB!FREEVERT!PROPBORDERLESS,d0
moveq #0,d1
moveq #0,d2
move.w _fsvposition,d2
move.l #$ffff,d3
moveq #0,d4
move.w _fsvheight,d4
moveq #1,d5
SYS NewModifyProp,_IntuitionBase
movem.l (sp)+,d2-d5/a2/a6
rts
; FSEnableFGad(gadg_num)
; LONG gadg_num;
;
; Given a file gadget number, refresh the text for that entry.
XDEF _FSEnableFGad
_FSEnableFGad:
movem.l a2-a3/a6,-(sp)
movea.l _FSRPort,a2
move.w 4+4*3+2(sp),d0 ;Grab gadget number
move.w d0,d1 ;Copy
lsl.w #2,d0 ;Conver to long offset
lea _FSFileNodes,a0
movea.l 0(a0,d0.w),a0 ;tnode = FSFileNodes[gadg_num]
movea.l fn_info(a0),a3 ;a3 = tnode->info
; Move to the right slot text position
mulu #11,d1
addi.w #19,d1
moveq #9,d0
movea.l a2,a1
SYS Move,_GfxBase ;Move(FSRPort, 9, gadnum*11+19)
; Set the pen color according to the node
move.w nd_textcolor(a3),d0
movea.l a2,a1
SYS SetAPen ;SetAPen(FSRPort, tinfo->textcolor)
; Blast out the text
moveq #56,d0
lea nd_alphadata(a3),a0
movea.l a2,a1
SYS Text ;Text(FSRPort, tinfo->alphadata, 56)
movem.l (sp)+,a2-a3/a6
rts
; FSDisableFGad(gadg_num)
; LONG gadg_num;
;
; Given a file gadget number, fill that slot with the EmptyPattern
; and clear the FileNode[] slot for that gadget.
XDEF _FSDisableFGad
_FSDisableFGad:
movem.l d2-d4/a2/a6,-(sp)
move.w 4*5+4+2(sp),d4 ;Grab gadget number
movea.l _FSRPort,a2
lea _EmptyPattern,a0
move.l a0,rp_AreaPtrn(a2) ;rp->AreaPtrn = EmptyPattern
move.b #1,rp_AreaPtSz(a2) ;rp->AreaPtSz = (BYTE)1
movea.l a2,a1
moveq #2,d0
SYS SetAPen,_GfxBase ;SetAPen(rp, 2)
move.w d4,d1
mulu #11,d1
addi.w #13,d1 ;miny = 13L + (gadg_num * 11)
move.l d1,d3
addq.w #7,d3 ;maxy = miny + 7L
movea.l a2,a1 ;FSWin->RPort
moveq #9,d0 ;minx
move.l #456,d2 ;maxx
SYS RectFill ;RectFill(rp, minx, miny, maxx, maxy)
clr.l rp_AreaPtrn(a2) ;rp->AreaPtrn = 0L
clr.b rp_AreaPtSz(a2) ;rp->AreaPtSz = (BYTE)0
move.w d4,d0
lsl.w #2,d0
lea _FSFileNodes,a0
clr.l 0(a0,d0.w) ;FSFileNodes[gadg_num] = 0L
movem.l (sp)+,d2-d4/a2/a6
rts
XDEF _FSDisableAllFGads
_FSDisableAllFGads:
move.l d2,-(sp)
moveq #0,d2
move.w _fsnumentries,d2
bra.s 2$
1$ move.l d2,-(sp)
jsr _FSDisableFGad ;FSDisableFGad(i)
addq.w #4,sp
addq.w #1,d2 ;i++
2$ cmpi.w #10,d2 ;Hit 10 entries?
bcs 1$ ;Nope, disable one
move.l (sp)+,d2
rts
;struct file_node *AllocFileNode()
;
; Allocate a file_node structure and it's info block, return pointer
; to the file_node or NULL if allocation failed.
XDEF _AllocFileNode
_AllocFileNode:
move.l a6,-(sp)
moveq #fn_SIZEOF+nd_SIZEOF,d0 ;sizeof(struct file_node)+sizeof(struct node_data)
move.l #MEMF_CLEAR,d1 ;MEMF_CLEAR
SYS AllocMem,4 ;Allocate file node structure
move.l d0,d1
beq.s 1$
movea.l d0,a0
addi.l #fn_SIZEOF,d1
move.l d1,fn_info(a0) ;Set pointer to tnode->info area
1$
movea.l (sp)+,a6
rts
; FreeFileNode(tnode)
; struct file_node *tnode;
;
; Given a pointer to a file_node, Free the memory allocated for that node.
XDEF _FreeFileNode
_FreeFileNode:
move.l a6,-(sp)
move.l 4+4(sp),d0 ;Grab tnode
beq.s 2$ ;Nope, get outta here
movea.l d0,a1
moveq #fn_SIZEOF+nd_SIZEOF,d0
SYS FreeMem,4 ;FreeMem(tnode, sizeof(struct file_node)+sizeof(struct node_data))
2$ movea.l (sp)+,a6
rts
; FreeAllFNodes()
;
; Call FreeFileNode for each node in the linked list of file_nodes,
;then deallocate the head of the list (fnList)
XDEF _FreeAllFNodes
_FreeAllFNodes:
movem.l a2/a6,-(sp)
move.l _fnList,d0 ;Is there a list?
beq.s 2$ ;Nope, get outta here
movea.l d0,a2 ;Grab head
movea.l 4,a6 ;Set for ExecBase
1$
movea.l a2,a0
SYS RemHead ;d0 = RemHead(fnList)
tst.l d0 ;Hit end?
beq.s 2$ ;yep
move.l d0,-(sp)
jsr _FreeFileNode ;Free the node
addq.w #4,sp
bra 1$ ;Remove next node
2$
; Reset other globals
clr.w _fsvposition ;Set slider position to top of area
move.w #$ffff,_fsvheight ;Max height
clr.w _fsnumentries ;Zero entries
movem.l (sp)+,a2/a6
rts
;struct dev_node *AllocDevNode()
;
; Allocate a dev_node, return pointer to same
XDEF _AllocDevNode
_AllocDevNode:
move.l a6,-(sp)
moveq #dn_SIZEOF,d0
move.l #MEMF_CLEAR,d1
SYS AllocMem,4 ;AllocMem(sizeof(struct dev_node), MEMF_CLEAR)
movea.l (sp)+,a6
rts
;FreeDevNode(tnode)
; struct dev_node *tnode;
;
; Given a pointer to a dev_node, free memory allocated for that node.
XDEF _FreeDevNode
_FreeDevNode:
move.l a6,-(sp)
move.l 4+4(sp),d0 ;Grab dev_node to free
beq.s 1$ ;Oops, nothing here
movea.l d0,a1
moveq #dn_SIZEOF,d0
SYS FreeMem,4 ;FreeMem(tnode, (long)sizeof(struct dev_node))
1$
movea.l (sp)+,a6
rts
;FreeAllDNodes()
;
; Call FreeDevNode() for each dev_node in the linked list, then free the
; head of the list, devList.
XDEF _FreeAllDNodes
_FreeAllDNodes:
movem.l a2/a6,-(sp)
move.l _devList,d0 ;Is there a head node?
beq.s 3$ ;Nope, don't deallocate
movea.l d0,a2 ;Grab head of device list
movea.l 4,a6 ;Set for execbase
1$ movea.l a2,a0
SYS RemHead ;d0 = RemHead(devList)
tst.l d0 ;Got one?
beq.s 2$ ;Nope, list is empty
move.l d0,-(sp)
jsr _FreeDevNode ;Free this device node
addq.w #4,sp
bra 1$
2$ movea.l a2,a1
moveq #MLH_SIZE,d0
SYS FreeMem ;FreeMem(devList, sizeof(MinList))
clr.l _devList
3$ movem.l (sp)+,a2/a6
rts
; FreeFileSelect()
; Deallocate filenames and fileinfoblocks, unlock any locks
XDEF _FreeFileSelect
_FreeFileSelect:
move.l a6,-(sp)
move.w #1,_fsvirgindir ;virgindir = 1
jsr _FreeAllFNodes ;Free all allocated filenames
jsr _FSClearLock ;Unlock any locks
; Free the head node itself
move.l _fnList,d0
beq.s 1$
movea.l d0,a1
moveq #MLH_SIZE,d0
SYS FreeMem,4 ;FreeMem(fnList, sizeof(MinList))
clr.l _fnList ;And clear the pointer
1$
; Free the global FileInfoBlock and InfoData struct
move.l _FSFib,d0 ;Do we have a FileInfoBlock allocated?
beq.s 2$ ;Nope
movea.l d0,a1
move.l #fib_SIZEOF+id_SIZEOF,d0
SYS FreeMem,4 ;FreeMem(FSFib, 300L)
clr.l _FSFib ;Set to NULL so we don't re-free it
clr.l _FSInfo
2$
movea.l (sp)+,a6
rts
; Cleanup function for fileselect
XDEF _ReleaseFileSelect
_ReleaseFileSelect:
jsr _FreeFileSelect
jsr _FreeAllDNodes
rts
; LONG FSGetNextFib(VOID)
;
; Call ExNext() to fill in next FileInfoBlock, set titlebar to reflect
; status of the request.
XDEF _FSGetNextFib
_FSGetNextFib:
movem.l d2/a6,-(sp)
* Try to get next fileinfoblock from dos
move.l _FSLock,d1
move.l _FSFib,d2
SYS ExNext,_DOSBase
tst.l d0 ;Did we get an entry?
bne.s gnfgot1 ;Yep, got it
; Didn't get one, find out why
; if ( (error = IoErr()) != ERROR_NO_MORE_ENTRIES)
SYS IoErr ;Get error number
cmpi.l #232,d0 ;No more entries?
beq.s gnfnme ;Yep
move.l d0,-(sp)
jsr _ioerrnum ;Otherwise set window title to error number
addq.w #4,sp
move.w d0,_fstitstatus
moveq #-1,d2 ;Return bad get status
bra.s gnfsetwintit
gnfnme:
moveq #0,d2 ;Return DONE!
tst.w _fsnumentries ;Got any valid pattern matches?
bne.s gnfselect ;Yep, select a file time
movea.l _fnList,a6
movea.l MLH_HEAD(a6),a6
tst.l fn_Node+MLN_SUCC(a6) ;Do we have any files?
beq.s gnfnoentry ;Nope, no entries
move.w #24,_fstitstatus ;Otherwise no match
bra.s gnfsetwintit
gnfnoentry:
move.w #22,_fstitstatus ;No Entries...
bra.s gnfsetwintit
gnfselect:
move.w #29,_fstitstatus ;Select a file...
gnfsetwintit:
bra.s gnfdone
gnfgot1:
moveq #1,d2
gnfdone:
move.l d2,d0
movem.l (sp)+,d2/a6
rts
;AllocFSFib()
;Allocate a fileinfoblock, return status
XDEF _AllocFSFib
_AllocFSFib:
move.l a6,-(sp)
tst.l _FSFib ;Do we already have a fib?
bne.s 1$ ;Yep, get out of here
;FSFib = AllocMem(sizeof(*FSFib) + sizeof(*FSInfo), MEMF_CLEAR);
move.l #fib_SIZEOF+id_SIZEOF,d0
move.l #MEMF_CLEAR,d1
SYS AllocMem,4
move.l d0,_FSFib
beq.s 2$ ;Oops, allocation failed, return 0
addi.l #fib_SIZEOF,d0
move.l d0,_FSInfo ;Set pointer to InfoData struct too
1$ moveq #1,d0 ;Return good status
2$ movea.l (sp)+,a6
rts
;LONG ioerrnum(num)
; LONG num;
;
; Given an IoErr number, convert to error text table offset, return
; converted index number.
XDEF _ioerrnum
_ioerrnum:
move.l 4(sp),d0
cmpi.w #202,d0 ;if (num < 202L || num > 231L)
bcs.s ioetl
cmpi.w #231,d0
bls.s ioe3l
ioetl:
moveq #27,d0 ;return(27)
rts
ioe3l:
cmpi.w #209,d0 ;if (num < 209L)
bcc.s ioe4l
subi.w #202,d0 ;num -= 202L
rts
ioe4l:
subi.w #205,d0 ;else num -= 205L
rts
; BYTE *ioerrmsg(num)
; long num;
;
; Given a IoErr number, return pointer to error message text that
; describes that error.
XDEF _ioerrmsg
_ioerrmsg:
move.l 4(sp),-(sp) ;Push error number
jsr _ioerrnum
addq.w #4,sp
lsl.w #2,d0 ;Convert return to text table offset
lea _fserrmsgs,a0
move.l 0(a0,d0.w),d0 ;Return pointer to fserrmsgs[num]
rts
; VOID FSPutPath(VOID)
; Refresh the FSPathGadget imagery.
XDEF _FSPutPath
_FSPutPath:
movem.l a2/a6,-(sp)
;RefreshGList(&FSPathGad, FSWin, 0L, 1L);
lea _FSPathGad,a0
movea.l _FSWin,a1
suba.l a2,a2
moveq #1,d0
SYS RefreshGList,_IntuitionBase
movem.l (sp)+,a2/a6
rts
; VOID FSClearLock(VOID)
;
; If we have a Lock on the current directory, unlock it.
XDEF _FSClearLock
_FSClearLock:
move.l a6,-(sp)
tst.w _fsdirlocked ;Is it locked?
beq.s 2$ ;Nope, don't dare unlock
move.l _FSLock,d1
beq.s 1$
SYS UnLock,_DOSBase ;UnLock(FSLock)
clr.l _FSLock ;FSLock = 0L;
1$ clr.w _fsdirlocked ;dirlocked = 0
2$ movea.l (sp)+,a6
rts
; FSWinTitle()
; Refresh current window title using contents of windowtitle[].
XDEF _FSWinTitle
_FSWinTitle:
movem.l a2/a6,-(sp)
move.w _fstitlelength,d0
lea _FSWinTitleStr,a0
clr.b 0(a0,d0.w) ;windowtitle[fstitlelength] = '\x0'
move.w _fstitstatus,d1
lsl.w #2,d1
lea _fserrmsgs,a1
movea.l 0(a1,d1.w),a1
adda.w d0,a0
jsr astrcpy ;astrcpy(&windowtitle[fstitlelength], fserrmsgs[fstitstatus])
movea.l _FSWin,a1
move.l wd_Flags(a1),d0 ;d0 = FSWin->Flags
andi.l #WINDOWTGADS,d0 ;Do we have titlebar gadgets?
bne.s 3$ ;Yep, refresh is automatic
lea _FSWinTitleStr+79,a1
clr.b (a1) ;FSWinTitleStr[79] = 0
move.b #' ',d0 ;for (;ptr != &FSWinTitle[79];ptr++)
2$ cmpa.l a0,a1
beq.s 4$
move.b d0,(a0)+ ;*ptr = ' '
bra 2$
3$
move.b #' ',(a0)+ ;Concat a space and a null onto the end
clr.b (a0)
4$
;SetWindowTitles(FSWin, windowtitle, -1L)
movea.l _FSWin,a0
lea _FSWinTitleStr,a1
movea.l #-1,a2
SYS SetWindowTitles,_IntuitionBase
movem.l (sp)+,a2/a6
rts
; VOID FSEndString(VOID)
;
; If user started a string gadget entry then clicked in another gadget,
;ignore any changes to the string and restore the previous string.
XDEF _FSEndString
_FSEndString:
movem.l a2/a6,-(sp)
move.w _fsstartedstr,d0 ;Grab starttext flag
cmpi.w #1,d0 ;Did user start at file entry?
bne.s fstnotfile ;Nope
movea.l _FSFileInfo,a0 ;Grab filename buffer
lea _FileUndoName,a1
lea _FSFileGad,a2 ;Grab filetext gadget
bra.s fstrefresh ;Refresh it
fstnotfile:
cmpi.w #2,d0 ;Did user start a path entry?
bne.s fstnotpath ;Nope, maybe pattern
movea.l _FSPathInfo,a0 ;Grab pathtext buffer
lea _FileUndoBuffer,a1
lea _FSPathGad,a2 ;Pointer to path gadget
bra.s fstrefresh ;Refresh text
fstnotpath:
cmpi.w #3,d0 ;Started a pattern entry?
bne.s fstdone ;Nope, don't have to do anything
movea.l _FSPatternInfo,a0 ;Else grab the pattern buffer
lea _FSPatternUndoBuffer,a1
lea _FSPatternGad,a2 ;Pointer to pattern gadget
fstrefresh:
jsr astrcpy ;astrcpy(tstr, FSwstr)
movea.l a2,a0
movea.l _FSWin,a1
suba.l a2,a2
moveq #1,d0
SYS RefreshGList,_IntuitionBase ;RefreshGList(tgad, FSWin, 0L, 1L)
clr.w _fsstartedstr ;fsstartedstr = 0
fstdone:
movem.l (sp)+,a2/a6
rts
; FSDoGadget(gadgid)
; ULONG gadgid;
;
; Given a gadget id number, perform action associated with that gadget.
XDEF _FSDoGadget
_FSDoGadget:
movem.l d4/a2,-(sp)
move.w 14(sp),d4 ;Grab gadget id number
bne.s dgnotusergad ;Not zero, not Undo gadget
; FSUserGad
jsr _ConcatPathString ;Concat final output text, return
clr.w _FSDone
movea.l _FSReq,a1
movea.l fs_specgadfunc(a1),a0
pea _FSUserGad
move.l _FSWin,-(sp)
move.l a1,-(sp)
jsr (a0)
lea 12(sp),sp
tst.l d0
bne dgnewdir
bra dogaddone
dgnotusergad:
; FSSelectGad
cmpi.w #1,d4 ;Is the the FSSelect gadget?
bne.s dgnotselect ;Nope
jsr _ConcatPathString ;Concat final output text, return
bra dogaddone
dgnotselect:
; FSCancelGad
cmpi.w #2,d4 ;Is it the FSCancel Gadget?
bne.s dgnotcancel ;Nope
move.w #1,_FSDone ;Global signal that we're done
movea.l _FSReq,a0 ;a0 = fsreq
movea.l fs_fullname(a0),a0 ;a0 = fsreq->fullname
clr.b (a0) ;Return filename == ""
bra dogaddone
dgnotcancel:
; UndoGad
cmpi.w #3,d4 ;Undo?
bne.s dgnotundo
movea.l _FSPathInfo,a0 ;Copy OldFSPathBuf to FSPathInfo.Buffer
movea.l _OldFSPathBuf,a1
jsr astrcpy ;astrcpy(FSPathInfo.Buffer, OldFSPathBuf)
bra dgnewdir ;Process new directory
dgnotundo:
; Dev1Gad
cmpi.w #20,d4 ;Is it the first Device Gadget?
bne.s dgnotram ;Nope
movea.l _CurDevNames+12,a1 ;Push the name text
dgdevs:
movea.l _FSPathInfo,a0 ;Destination text
jsr astrcpy ;Copy new path
bra dgnewdir ;Now set new directory
dgnotram:
cmpi.w #21,d4 ;Is it the second Device Gadget?
bne.s dgnotdf0 ;Nope
movea.l _CurDevNames+8,a1 ;Push the name text
bra dgdevs ;Change path
dgnotdf0:
cmpi.w #22,d4 ;Is it the third Device Gadget?
bne.s dgnotnil1 ;Nope
movea.l _CurDevNames+4,a1 ;Push the name text
bra dgdevs ;Set the path
dgnotnil1:
cmpi.w #23,d4 ;Is it the fourth Device Gadget?
bne.s dgnotnil2 ;Nope
movea.l _CurDevNames,a1 ;Push the name text
bra dgdevs ;And set the new path
dgnotnil2:
; RootGad
cmpi.w #24,d4 ;Is it the ROOT gadget?
bne.s dgnotroot ;Nope
jsr _SetRootDir ;Set root directory!
bra dogaddone ;Done
dgnotroot:
; ParentGad
cmpi.w #25,d4 ;Is it the Parent gadget?
bne.s dgnotpar ;Nope
jsr _SetParentDir ;Change to parent directory
bra dogaddone ;Done!
dgnotpar:
; FSPatternGad
cmpi.w #30,d4 ;Maybe its the pattern text gadget?
bne.s dgnotpattern
jsr _FSMatchPattern ;Otherwise attempt to match new pattern
bra dogaddone ;We're done!
dgnotpattern:
; FSFileGad
cmpi.w #31,d4 ;Is it the file text gadget?
bne.s dgnotfileg ;Nope
jsr _FSFileFunc
jsr _ConcatPathString ;Form final path text
btst.b #1,_fsflags+1 ;FS_NO_STRING_EXIT?
beq dogaddone
clr.w _FSDone
bra dogaddone
1$
movea.l _FSFileInfo,a0
tst.b (a0) ;Really a filename here?
bne.s 2$ ;yep
btst.b #2,_fsflags+1 ;FS_NO_STRING_OKAY?
beq.s 2$ ;Nope
bra dogaddone ;let user exit with no filename
2$
clr.w _FSDone ;Else we ain't done yet!
bra dogaddone
dgnotfileg:
; FSPathGad
cmpi.w #32,d4 ;Is it the path text gadget?
bne.s dgnotpath ;Nope
movea.l _FSPathInfo,a2 ;Grab pointer to path text
movea.l a2,a0
jsr astrlen ;Determine length
subq.w #1,d0 ;Move back to last BYTE
blt.s dgnotdamnsla ;Oops, null text!
cmpi.b #'/',0(a2,d0.w) ;Is the last char a slash?
bne.s dgnotdamnsla ;Nope, don't have to tromp it
1$ cmpi.b #'/',0(a2,d0.w) ;Check for a trailing slash
bne.s 2$ ;Didn't find another
clr.b 0(a2,d0.w) ;Clobber this slash
subq.w #1,d0 ;Dec character pointer
bne.s 1$ ;till we run out of slashes or chars
2$ jsr _FSPutPath ;Refresh path text
dgnotdamnsla:
jsr _FSDirFunc ;Do fsreq->dirfunc, if there is one
tst.w d0 ;Ignore new dir?
beq.s 1$ ;Nope
jsr _SetParentDir ;Else chop off the new path
jsr _FSPutPath ;Update string gad
clr.w _fsvirgindir ;Virgin again
bra.s dogaddone ;All done
1$
move.l _FSWin,-(sp)
pea _FSFileGad
jsr _MyActivateGad ;Activate file text gadget
addq.w #8,sp
bra.s dgnewdir ;Set new path, read new dir
dgnotpath:
; Slide Gadget
cmpi.w #33,d4 ;Is it the SlideGadget?
bne.s dgnotslide ;nope
jsr _FSDoSlideGadget ;Else it's been released, update position
bra.s dgresetarrows ;Done here, reset timer
dgnotslide:
; Arrow gadgets
cmpi.w #40,d4 ;Is it one of the four arrows gadgets?
blt.s dogaddone
cmpi.w #43,d4
bgt.s dogaddone
dgresetarrows:
clr.w _FSCountDown ;Kill any timer requests in progress
bra.s dogaddone
dgnewdir:
move.w #1,_fsvirgindir ;Set flag to read new directory!
dogaddone:
movem.l (sp)+,d4/a2
rts
; VOID FillFileNode(tnode)
; struct file_node *tnode;
ffnnode EQU 4+4*4
XDEF _FillFileNode
_FillFileNode:
movem.l d2/a2-a3/a6,-(sp)
movea.l ffnnode(sp),a0 ;a0 = tnode passed
movea.l fn_info(a0),a2 ;a2 = tinfo = tnode->info
movea.l _FSFib,a3 ;a3 = FSFib
move.l fib_Size(a3),nd_filesize(a2) ;tinfo->filesize = FSFib->fib_Size
move.l fib_DateStamp+0(a3),nd_days(a2) ;tinfo->day = FSFib->fib_DateStamp.ds_Days
move.l fib_DateStamp+4(a3),nd_minutes(a2)
move.l fib_DateStamp+8(a3),nd_ticks(a2)
pea fib_DateStamp(a3)
jsr _FibFileDate
addq.w #4,sp
movea.l d0,a1
lea nd_alphadata(a2),a0 ;a0 = tinfo->alphadata
jsr astrcpy ;a0 = astrcpy(&tinfo->alphadata[0], FibFileDate(&FSFib->DateStamp))
tst.l fib_DirEntryType(a3) ;If < 0 it is a file
bge.s ffnisdir ;>= 0, it is a dir
ffnisfile:
move.w #1,nd_filetype(a2) ;tinfo->filetype = 1
move.w #FPEN,nd_textcolor(a2) ;tinfo->textcolor = FPEN
move.l a0,-(sp)
move.l fib_Size(a3),-(sp)
pea _FSSizeFmtStr
move.l a0,-(sp)
jsr _sprintf ;sprintf(a0, "%8ld ", FSFib->fib_Size)
lea 12(sp),sp
movea.l (sp)+,a0
adda.w #9,a0 ;Skip filesize part of message
bra.s ffnsetname
ffnisdir:
move.w #2,nd_filetype(a2) ;tinfo->filetype = 2
move.w #DPEN,nd_textcolor(a2) ;tinfo->textcolor = DPEN
lea _FSDirFmtStr,a1
jsr astrcpy ;astrcpy(dest, FSDirFmtStr)
ffnsetname:
moveq #0,d0
lea fib_FileName(a3),a1 ;a1 = FSFib->fib_FileName
1$ move.b (a1)+,d1
beq.s 2$ ;Hit null, see if we need to pad
move.b d1,(a0)+ ;copy a char, till null
addq.w #1,d0 ;i++
cmpi.w #30,d0 ;Max chars yet?
bcs 1$
2$ move.w d0,nd_namelength(a2) ;tinfo->namelength = i
move.b #' ',d1
bra.s 4$ ;Append spaces till 30 chars
3$ move.b d1,(a0)+
addq.w #1,d0
4$ cmpi.w #30,d0
bcs 3$
clr.b (a0) ;Null terminate at 31st char
ffnsetshow:
movea.l ffnnode(sp),a2
moveq #1,d0
movea.l a2,a0 ;a0 = tnode
jsr _FSValidateEntry ;FSValidateEntry(tnode, 1)
; Now insert the node into list according to sort type
ffninsert:
movea.l _fnList,a3
movea.l MLH_HEAD(a3),a3 ;a3 = fnList->lh_Head
movea.l _FSReq,a0
move.w fs_sorttype(a0),d2 ;d0 = FSReq->sorttype
1$
tst.l fn_Node+MLN_SUCC(a3) ;Is this the end of the list?
beq.s 2$ ;Nope, insert it here
move.l fn_info(a3),a1 ;Push existing node->info
move.l fn_info(a2),a0 ;Push tnode->info
move.w d2,d0 ;Push sort type
jsr _CompareNodes ;Compare info's according to sort type
tst.w d0 ;Is a0 > a1?
beq.s 2$ ;nope, found insertion point
movea.l fn_Node+MLN_SUCC(a3),a3 ;oldnode = oldnode->next
bra 1$ ;Nope, keep looking
2$
movea.l _fnList,a0
movea.l a2,a1
move.l fn_Node+MLN_PRED(a3),a2
SYS Insert,4
ffndone:
movem.l (sp)+,d2/a2-a3/a6
rts
; VOID FSValidateEntry(tnode, mode)
; a0 d0
XDEF _FSValidateEntry
_FSValidateEntry:
movem.l d2-d3/a2,-(sp)
; See if the Acceptor likes this node name
move.l d0,d3 ;d3 = mode
movea.l a0,a2 ;a2 = tnode
move.l a2,-(sp)
jsr _FSAcceptEntry ;if (FSAcceptEntry(tnode) == 0)
addq.w #4,sp
tst.w d0
bne.s 1$
; Don't display this node
movea.l fn_info(a2),a0
clr.w nd_showit(a0) ;tnode->info->showit = 0;
move.w #-1,fn_idnum(a2) ;tnode->idnum = -1
bra.s 4$ ;And return
; Accept this node for display
1$ movea.l fn_info(a2),a0
move.w #1,nd_showit(a0) ;else tnode->info->showit = 1;
moveq #0,d2
move.w _fsnumentries,d2 ;Grab entry number for this node
bne.s 2$ ;Not first entry
move.l a2,_topfin ;topnode = tnode, first visible node
2$
move.w d2,fn_idnum(a2) ;tnode->idnum = fsnumentries
addq.w #1,_fsnumentries ;fsnumentries++, one more visible entry
clr.w _fsneedshow ;fsneedshow = 0, needs sorting
; If we haven't filled display area, show this entry
cmpi.w #10,d2 ;> 10 entries already?
bcc.s 3$ ;Yep, just set the knob
lea _FSFileNodes,a0
move.w d2,d0 ;Grab entry number
lsl.w #2,d0 ;Convert to long table offset
move.l a2,0(a0,d0.w) ;FSFileNodes[fsnumentries] = tnode
move.l d2,-(sp)
jsr _FSEnableFGad ;FSEnableFGad(fsnumentries)
addq.w #4,sp
bra.s 4$ ;Skip setting knob, it is still full size
3$
tst.w d3 ;Want slide update?
beq.s 4$ ;Nope
btst.b #7,_FSSlideGad+gg_Flags+1 ;User has slide gadget in use?
bne.s 4$ ;Yes, don't refresh it while in use
; Calc new knob size and refresh
btst.l #0,d2 ;(idnum % 2) == 0?
beq.s 4$ ;Yep, don't reset on even values
jsr _FSResetKnob
4$
movem.l (sp)+,d2-d3/a2
rts
; Update FileTexts list, redisplay
; Renumber list, find new topfin
XDEF _FSUpdateSort
_FSUpdateSort:
move.w _fsneedshow,d0
blt.s 3$
move.w _fsnumentries,d1
beq.s 2$
subi.w #10,d1 ;Less max number of visible files
move.w _FSSlideProp+4,d0 ;Grab current vpot
mulu d1,d0 ;Times position percentage
addi.l #32768,d0
clr.w d0
swap d0
jsr _FSResetNumEntries
jsr _FSSetFileGads
2$
move.w #-1,_fsneedshow
moveq #0,d0
3$ tst.w d0
rts
; VOID FSResetNumEntrys(idnum)
; d0:16
XDEF _FSResetNumEntries
_FSResetNumEntries:
move.l a2,-(sp)
movea.l _fnList,a2 ;Grab List
movea.l MLH_HEAD(a2),a2 ;Head of list
moveq #0,d1 ;i = 0
1$ tst.l fn_Node+MLN_SUCC(a2) ;End of list?
beq.s 5$
movea.l fn_info(a2),a0 ;a0 = tnode->info
tst.w nd_showit(a0) ;Visible?
bne.s 2$ ;Yep
move.w #-1,fn_idnum(a2) ;Else tnode->idnum = -1
bra.s 4$ ;Next node
2$ move.w d1,fn_idnum(a2) ;tnode->idnum = i
cmp.w d1,d0 ;if (idnum == oldidnum)
bne.s 3$
move.l a2,_topfin ; topfin = tnode;
3$
addq.w #1,d1 ;i++
4$
movea.l fn_Node+MLN_SUCC(a2),a2 ;tnode = tnode->fn_Node.mln_Succ
bra 1$ ; Check next node
5$
move.w d1,_fsnumentries ;Update number of entries
movea.l (sp)+,a2
rts
; LONG FSAcceptEntry(struct file_node *tnode);
; Decide whether given tnode is displayable.
; Return 0L for ignore this node, 1L for valid node.
aftnode EQU 8
aftname EQU -48
XDEF _FSAcceptEntry
_FSAcceptEntry:
link a5,#aftname
movem.l a2-a3,-(sp)
movea.l aftnode(a5),a2 ;Grab tnode
movea.l fn_info(a2),a3 ;Grab tnode->info
; Copy tnode->info->alphadata name section to stack, null terminate
move.w nd_namelength(a3),d0 ;Push tinfo->namelength
lea nd_alphadata+26(a3),a1 ;Push tinfo->alphadata + 26
lea aftname(a5),a0 ;Push destination
jsr astrncpy ;Copy and null terminate
; If there is a special match function defined, use that...
movea.l _FSReq,a0
tst.l fs_matchfunc(a0) ;If FSReq->matchfunc != 0
beq.s 1$
move.l aftnode(a5),-(sp)
pea aftname(a5)
move.l _FSReq,-(sp)
move.l fs_matchfunc(a0),a0
jsr (a0) ;return((FSReq->matchfunc)(FSReq, name, tnode)
lea 12(sp),sp
bra.s aftdone
; Otherwise use built-in acceptor routine
1$ cmpi.w #2,nd_filetype(a3) ;Is tinfo->filetype == 2? (a directory)
beq.s aftisdir ;Yep, we need it in list
; Check file name against patterns
btst.b #6,_fsflags+1 ;Want dirs only?
bne.s aftwrongpat ;Yep, ignore all files
pea _FSIgnorePat ;See if it matches the ignore text
pea aftname(a5)
jsr _wildmatch
addq.w #8,sp
tst.w d0 ;Did it match the ignore text?
bne.s aftwrongpat ;Yep, ignore this file
move.l _FSPatternInfo,-(sp) ;See if it matches desired pattern
pea aftname(a5)
jsr _wildmatch
addq.w #8,sp
tst.w d0 ;Did it match?
beq.s aftwrongpat ;Nope, skip it
bra.s aftgoodpat ;Else accept this file
aftisdir:
btst.b #5,_fsflags+1 ;This is a dir, want files only?
bne.s aftwrongpat ;Yep, ignore this dir
aftgoodpat:
moveq #1,d0 ;Accept this entry
bra.s aftdone
aftwrongpat:
moveq #0,d0 ;Ignore this entry
aftdone:
movem.l (sp)+,a2-a3
unlk a5
rts
; VOID FSMatchPattern(VOID);
; Called when path or pattern has changed - rematch all entries
; against the new pattern, display entries that match.
XDEF _FSMatchPattern
_FSMatchPattern:
movem.l d4/a2-a3/a6,-(sp)
; Pattern match list against new pattern, flag unwanted names
movea.l _FSPatternInfo,a0 ;Grab pattern
tst.b (a0) ;Null pattern text?
bne.s mnpnotnop ;Nope, process it
move.b #'*',(a0)+ ;Otherwise put back wildstar
clr.b (a0) ;Null terminate
lea _FSPatternInfo,a0 ;Grab stringinfo
move.w #1,8(a0) ;FSPatternInfo.BufferPos = 1;
lea _FSPatternGad,a0
movea.l _FSWin,a1
suba.l a2,a2
moveq #1,d0
SYS RefreshGList,_IntuitionBase ;Refresh pattern text gadget
move.l _FSWin,-(sp)
pea _FSPatternGad
jsr _MyActivateGad ;MyActivateGad(&FSPatternGad, FSWin)
addq.w #8,sp
bra.s mnpdone ;Make the user type something else in
mnpnotnop:
movea.l _fnList,a0
move.l MLH_HEAD(a0),a0
tst.l fn_Node+MLN_SUCC(a0) ;Do we have any files to match?
beq.s mnpdone ;Nope, nothing to do
; Reset knob to full height, zero position
clr.w _fsnumentries ;Clear fsnumentries count
clr.w _fsvposition
move.w #$ffff,_fsvheight
jsr _FSSetKnob ;Show new knob
; Disable all file "gadgets"
jsr _FSDisableAllFGads
; Scan list, enable/flag entries that match new pattern
movea.l _fnList,a2 ;tnode = fnList
movea.l MLH_HEAD(a2),a2 ;tnode = head node
clr.l _topfin ;Clear out top/bot display pointers
1$
tst.l fn_Node+MLN_SUCC(a2) ;End of list?
beq.s 2$
moveq #0,d0
movea.l a2,a0
jsr _FSValidateEntry ;FSValidateEntry(tnode, 0)
movea.l fn_Node+MLN_SUCC(a2),a2 ;tnode = tnode->fn_Node.mln_Succ
bra 1$ ;Nope, process this one too
2$
move.w #-1,_fsneedshow ;Clear reshow/sort flag, list valid
cmpi.w #10,_fsnumentries ;Found some entries?
bls.s mnpsettitle ;Yep, skip setting knob again
jsr _FSResetKnob ;Show new knob size
mnpsettitle:
tst.w _fsnumentries ;Got any matches to pattern?
bne.s mnpmatchedsome ;Yep
move.w #24,_fstitstatus ;"Nothing matched PATTERN"
bra.s mnpnewtit
mnpmatchedsome:
move.w #29,_fstitstatus ;"Select a file..."
mnpnewtit:
jsr _FSWinTitle ;Show final title status
mnpdone:
movem.l (sp)+,d4/a2-a3/a6
rts
; VOID ConcatPathString(VOID)
;
; If the file text is non-NULL, concat path text and file text,
; set global exit flag to show user selected a filename.
XDEF _ConcatPathString
_ConcatPathString:
; Try to add path prefix
move.l _FSFileInfo,-(sp)
move.l _FSPathInfo,-(sp)
movea.l _FSReq,a0 ;Grab final pathtext
movea.l fs_fullname(a0),a0
move.l a0,-(sp)
jsr _ConcatDirFile ;ConcatDirFile(FSReq->fullname, FSPathInfo->Buffer, FSFileInfo->Buffer)
lea 12(sp),sp
; Did the user select a filename yet?
movea.l _FSFileInfo,a0
tst.b (a0) ;First byte of name null?
bne.s 1$ ;Nope, must be okay
btst.b #2,_fsflags+1 ;(FSFlags & FS_NO_STRING_OKAY) == 0?
beq.s 2$ ;Yep, user can't exit till something is entered
1$
; Flag main loop to exit
move.w #1,_FSDone
2$
rts
; VOID __stdargs ConcatDirFile(BYTE *, BYTE *, BYTE *)
XDEF _ConcatDirFile
_ConcatDirFile:
movem.l 4(sp),a0-a1 ;grab dest, dirname
tst.b (a1) ;Is there a dirname here?
beq.s 1$ ;Nope
jsr astrcpy ;astrcpy(dest, dirname)
movea.l 12(sp),a1 ;grab filename
tst.b (a1) ;Is there a filename?
beq.s 2$ ;Nope, don't concat a slash
move.b -1(a0),d0 ;d0 = dest[strlen(dest - 1)]
cmpi.b #':',d0 ;Already has a colon?
beq.s 1$ ;Yep
cmpi.b #'/',d0 ;Already has a slash?
beq.s 1$ ;Yep
move.b #'/',(a0)+ ;Append a slash
clr.b (a0) ;Terminate
1$
movea.l 12(sp),a1
jsr astrcpy ;astrcpy(dest, name)
2$
rts
; VOID FSDoSlideGadget(VOID)
;
; Process the current slide gadget position, scroll file entries
; to match current position.
XDEF _FSDoSlideGadget
_FSDoSlideGadget:
movem.l d4-d5,-(sp)
jsr _FSUpdateSort
beq dsgdone
cmpi.w #10,_fsnumentries ;Do we have less than 10 entries?
blt dsgdone ;Yep, can't move anyhow
moveq #0,d0
move.w _FSSlideProp+4,d0 ;Grab new vpot
cmp.w _fsvposition,d0 ;Has it moved?
beq dsgdone ;Nope
move.w d0,_fsvposition ;Otherwise update position
move.w _fsnumentries,d4 ;Grab number of entries
subi.w #10,d4 ;Less max number of visible files
mulu d0,d4 ;Times position percentage
addi.l #32768,d4
clr.w d4
swap d4
movea.l _topfin,a0 ;Grab top node
cmp.w fn_idnum(a0),d4 ;Is node->idnum the same as newpos?
beq.s dsgdone ;Yep, don't have to move it
bcc.s dsgscrup ;newpos is lower, scroll up
; Scroll Down
move.w fn_idnum(a0),d0 ;Grab topfin->idnum
sub.w d4,d0 ;i = idnum - newpos
cmpi.w #8,d0 ;Need to scroll more than 8?
ble.s dsgssdwn ;Nope, use slow scroll
dsgdwn1:
cmp.w fn_idnum(a0),d4 ;Is topfin->idnum == newpos yet?
beq.s dsgredo ;Yep, we are done
dsgpretop:
movea.l fn_Node+MLN_PRED(a0),a0 ;topfin = topfin->fn_Node.mln_Pred
tst.w fn_idnum(a0) ;Is this idnum >= 0?
blt.s dsgpretop ;Nope, keep looking
bra.s dsgdwn1 ;Check this new position
dsgssdwn:
move.l d0,-(sp)
jsr _FSScrollDownGads ;Scroll entries down d5 times
addq.w #4,sp
bra.s dsgdone
; Scroll Up
dsgscrup:
move.w d4,d5 ;Grab newpos
sub.w fn_idnum(a0),d5 ;i = newpos - node->idnum
cmpi.w #8,d5 ;i > 8?
ble.s dsgssup ;Nope, use slow scroll
dsgmvup1:
cmp.w fn_idnum(a0),d4 ;Is topfin->idnum == newpos yet?
beq.s dsgredo ;Yep, we are done
dsgnxttop:
movea.l fn_Node+MLN_SUCC(a0),a0 ;topfin = topfin->fn_Node.mln_Succ
tst.w fn_idnum(a0) ;Is this a valid entry?
blt.s dsgnxttop ;Nope, move on
bra.s dsgmvup1
dsgredo:
move.l a0,_topfin ;Set new top and bottom
jsr _FSSetFileGads ;Redraw all the file entries
bra.s dsgdone ;We're done
dsgssup:
move.l d5,-(sp)
jsr _FSScrollUpGads ;Scroll the entries up d5 times
addq.w #4,sp
dsgdone:
movem.l (sp)+,d4-d5
rts
; VOID FSStartScrollGad(gadcode)
; ULONG gadcode;
; Given Gadget ID code, respond to first user click on a arrow gadget.
; Reset the timer.device so that .25 seconds delay occurs before
; the autorepeat kicks in.
XDEF _FSStartScrollGad
_FSStartScrollGad:
move.w 6(sp),d0 ;Grab gadget code
subi.w #33,d0 ;Slide gad
bne.s 1$
jsr _FSDoSlideGadget
clr.w _FSCountDown
rts
1$
subi.w #7,d0 ;33+7=40, UpGad
bne.s 2$
pea 1
11$ jsr _FSScrollFileGads
addq.w #4,sp
bra.s ssgdone
2$
subq.w #1,d0 ;33+7+1=41, DownGad
bne.s 3$
pea 0
bra 11$
3$
subq.w #1,d0 ;33+7+2=42, UpDev
bne.s 4$
pea 1
33$ jsr _FSScrollDevGads
addq.w #4,sp
bra.s ssgdone
4$
subq.w #1,d0 ;33+7+3=43, DownDev
bne.s ssgrts
pea 0
bra 33$
ssgdone:
move.w #4,_FSCountDown
ssgrts:
rts
; FSScrollFileGads(direction)
; BOOL direction;
;
; Scroll the file entries up or down by 1
; if (direction == 0)
; scrollup;
; else
; scrolldown;
XDEF _FSScrollFileGads
_FSScrollFileGads:
;if (fsnumentries > 10)
cmpi.w #10,_fsnumentries ;Less than 10 entries?
ble.s sfgdone ;Yep, can't scroll anyhow
;if (direction)
; FSScrollDownGads(1);
tst.w 6(sp) ;ScrollDown?
beq.s sfgup ;Nope, scroll up
pea 1
jsr _FSScrollDownGads
addq.w #4,sp
bra.s sfgpos
sfgup:
;FSScrollUpGads(1)
pea 1
jsr _FSScrollUpGads
addq.w #4,sp
sfgpos:
; Reset the slide knob position the display movement
jsr _FSSetKnobPos
jsr _FSSetKnob ;Set new knob position
sfgdone:
rts
; FSScrollUpGads(count)
; LONG count;
;
; Single-step scroll the file entries up count times.
XDEF _FSScrollUpGads
_FSScrollUpGads:
link a5,#0
movem.l d2-d7/a2/a6,-(sp)
jsr _FSUpdateSort
beq.s sugdone
movea.l _FSRPort,a2
;for (i = 0; i < count; i++)
moveq #0,d7
bra.s sugchk1
sugloop1:
; If the bottom entry is not the last entry, scroll it up
movea.l _topfin,a0 ;Grab top visible node
move.w fn_idnum(a0),d0 ;Grab id number
addi.w #11,d0 ;Plus 11
cmp.w _fsnumentries,d0 ;Compare to last known entry
bgt.s sugdone ;Yep, can't scroll up any more
; Bump the top pointer down the list to the next visible entry
movea.l _topfin,a0
1$ move.l fn_Node+MLN_SUCC(a0),a0 ;topfin = topfin->fn_Node.mln_Succ
tst.w fn_idnum(a0) ;while (topfin->idnum < 0)
blt 1$ ;Not a valid entry
move.l a0,_topfin ;Here's our new top entry node
; Now reassign the visible file gadget array to the new node list
jsr _FSAssignNodes
; Display new file entries and redraw borders
;ClipBlit(rp, 9L, 24L, rp, 9L, 13L, 447L, 96L, 0xc0L);
movea.l a2,a0
moveq #9,d0
moveq #24,d1
movea.l a2,a1
moveq #9,d2
moveq #13,d3
move.l #447,d4
moveq #96,d5
move.l #$0c0,d6
SYS ClipBlit,_GfxBase
;FSEnableFGad(9);
move.l #9,-(sp)
jsr _FSEnableFGad ;Now draw the new gadget at bottom
addq.w #4,sp
addq.w #1,d7 ;Bump scroll count
sugchk1:
cmp.w 10(a5),d7 ;Have we scrolled enough?
blt sugloop1 ;Nope, do again
sugdone:
movem.l (sp)+,d2-d7/a2/a6
unlk a5
rts
; FSScrollDownGads(count)
; LONG count;
;
; Single-step scroll the file entries down count times.
XDEF _FSScrollDownGads
_FSScrollDownGads:
link a5,#0
movem.l d2-d7/a2/a6,-(sp)
jsr _FSUpdateSort
beq.s sdgdone
movea.l _FSRPort,a2
;for (i = 0; i < count; i++)
moveq #0,d7
bra.s sdgchk1
sdgloop1:
;If the top entry is not the first entry, scroll it down
movea.l _topfin,a0 ;Grab top node
tst.w fn_idnum(a0) ;idnum == 0?
beq.s sdgdone ;Yep, can't scroll down any more
; Bump the top and bottom entry pointers down the list
1$ movea.l fn_Node+MLN_PRED(a0),a0 ;topfin = topfin->fn_Node.mln_Pred
tst.w fn_idnum(a0) ;while (topfin->idnum < 0)
blt 1$
move.l a0,_topfin ;New topfin
; Now reassign the visible file gadget array to the new node list
jsr _FSAssignNodes
; Display new file entries and redraw borders
;ClipBlit(rp, 9L, 13L, rp, 9L, 24L, 447L, 96L, 0xc0L)
movea.l a2,a0
moveq #9,d0
moveq #13,d1
movea.l a2,a1
moveq #9,d2
moveq #24,d3
move.l #447,d4
moveq #96,d5
move.l #$0c0,d6
SYS ClipBlit,_GfxBase
;FSEnableFGad(0);
pea 0
jsr _FSEnableFGad ;Display the only new "gadget"
addq.w #4,sp
addq.w #1,d7 ;Bump scroll count
sdgchk1:
cmp.w 10(a5),d7 ;Have we scrolled enough?
blt sdgloop1 ;Nope, do again
sdgdone:
movem.l (sp)+,d2-d7/a2/a6
unlk a5
rts
; VOID FSAssignNodes(VOID)
XDEF _FSAssignNodes
_FSAssignNodes:
movem.l a2-a3,-(sp)
;for (tnode = topfin, i = 0; ;tnode = tnode->next)
lea _FSFileNodes,a3 ;Grab base address of array of filegadgets
movea.l _topfin,a2 ;Grab our top visible filenode
moveq #10,d0 ;Fill 10 gadgets max
ran1:
tst.l fn_Node+MLN_SUCC(a2) ;Succ == 0?
beq.s ragdone ;Ran out of list entries
;if (tnode->idnum >= 0)
tst.w fn_idnum(a2) ;Is this name "visible"?
blt.s ragchkbot ;Nope, skip it
move.l a2,(a3)+ ;FSFileNodes[i] = tnode
subq.w #1,d0 ;One less slot available
beq.s ragdone ;Filled all the slots, exit loop
ragchkbot:
movea.l fn_Node+MLN_SUCC(a2),a2
bra ran1 ;check next node
ragdone:
movem.l (sp)+,a2-a3
rts
; VOID __stdargs FSDoFileGad(Ypos)
; LONG Ypos;
;
; Based on the mouse's Ypos passed, select file entry that user clicked.
XDEF _FSDoFileGad
_FSDoFileGad:
link a5,#0
movem.l d2-d4/a2-a3/a6,-(sp)
moveq #0,d4
move.w 10(a5),d4 ;Grab gadget y position
subi.w #12,d4 ;Less 12 (top edge of first entry)
divu #11,d4 ; divided by 11 (height of each entry)
ext.l d4 ;Blow remainder, this is our entry number
move.w d4,d0
lsl.w #2,d0 ;Convert to long offset
lea _FSFileNodes,a2 ;Grab base address of visible node_datas
movea.l 0(a2,d0.w),a3 ;Grab FSFileNodes[gadg_num]
cmpa.l #0,a3
beq dfgdone ;If zero, not a active "gadget" slot
;strncpy(FSwstr, tinfo->alphadata + 26L, tinfo->namelength)
movea.l fn_info(a3),a3 ;tinfo = tnode->info
lea _FSwstr,a2 ;Grab address of worktext
move.w nd_namelength(a3),d0 ;Push tinfo->namelength
lea nd_alphadata+26(a3),a1 ;Push tinfo->alphadata + 26
movea.l a2,a0 ;Push dest text
jsr astrncpy ;strncpy(FSwstr, filename, namelength)
;if (tinfo->filetype == 1)
cmpi.w #1,nd_filetype(a3) ;Did user click on a filename?
bne.s dfgnotfile ;Nope, must be a dir
;if ( strcmp(FSFileInfo.Buffer, FSwstr) )
movea.l a2,a1 ;Push FSwstr
movea.l _FSFileInfo,a0 ;Push address of filebuffer
jsr astrcmp
tst.w d0 ;Is this the same as what we already have?
beq.s dfgnsname ;Yep, see if it was double-clicked
;strcpy(FSFileInfo.Buffer, FSwstr)
movea.l a2,a1
movea.l _FSFileInfo,a0
jsr astrcpy ;Otherwise copy new filename to filebuffer
lea _FSFileGad,a0 ;And refresh filename text gadget
movea.l _FSWin,a1
suba.l a2,a2
moveq #1,d0
SYS RefreshGList,_IntuitionBase
bra dfgfiledone
dfgnsname:
;if ( DoubleClick(fsoldsecs, fsoldmicros, fscursecs, fscurmicros &&
; (gadg_num == fsprevgadid) )
; ConcatPathString();
btst.b #0,_fsflags+1 ;FS_NO_DCLICK_EXIT?
bne dfgfiledone ;Yep, programmer doesn't allow that
cmp.w _fsprevgadid,d4 ;Is it the same gadget?
bne dfgfiledone ;Nope, can't be a double click
move.l _fsoldsecs,d0
move.l _fsoldmicros,d1
move.l _fscursecs,d2
move.l _fscurmicros,d3
SYS DoubleClick,_IntuitionBase
tst.w d0 ;Is it within click speed parameters?
beq.s dfgfiledone ;Nope
jsr _ConcatPathString ;Construct full path text
bra.s dfgdone
;Clicked on a DIR
dfgnotfile:
cmpi.w #1,_fsvirgindir ;if (virgindir != 1)
beq.s dfgdone ;Don't concat if we haven't locked dir yet
;i = strlen(FSPathInfo.Buffer);
move.l _FSPathInfo,a0
jsr astrlen
move.w d0,d2 ;Length of stuff already in path text
;if ( (strlen(FSwstr) + i) < PATHSTRSIZE)
movea.l a2,a0
jsr astrlen
add.w d2,d0
cmpi.w #PATHSTRSIZE-1,d0
bge.s dfgtoodeep ;Don't append path if no room!
move.l a2,-(sp)
move.l _FSPathInfo,-(sp)
move.l _FSPathInfo,-(sp)
jsr _ConcatDirFile ;ConcatDirFile(FSPathInfo->Buffer, FSPathInfo->Buffer, FSwstr)
lea 12(sp),sp
jsr _FSDirFunc ;Do FSReq->dirfunc, if there is one
tst.w d0 ;Avoid reading this dir?
beq.s 1$ ;Nope, process it
move.l _FSPathInfo,a0
clr.b 0(a0,d2.w) ;Else FSPathInfo->Buffer[oldstrlen] = 0
bra.s dfgdone
1$
move.w #1,_fsvirgindir ;virgindir = 1, read the new directory
bra.s dfgdone
dfgtoodeep:
move.w #12,_fstitstatus ;fstitstatus = 12
jsr _FSWinTitle
suba.l a0,a0
SYS DisplayBeep,_IntuitionBase
bra.s dfgdone
dfgfiledone:
jsr _FSFileFunc ;Call FSReq->filefunc, if there is one
dfgdone:
move.w d4,_fsprevgadid ;fsprevgadid = gadg_num
movem.l (sp)+,d2-d4/a2-a3/a6
unlk a5
rts
; LONG FSDirFunc(VOID);
; If there is a fsrequest->dirfunc, this routine handles the interface.
XDEF _FSDirFunc
_FSDirFunc:
move.l d2,-(sp)
moveq #0,d0
movea.l _FSReq,a0 ;Grab our FSRequest struct
move.l fs_dirfunc(a0),d2 ;Is there a user dir function to call?
beq.s 1$ ;Nope, that's all we have to do this click!
jsr _ConcatPathString ;Combine dir/file as fullname for return
clr.w _FSDone ;Not done though, undo return status
move.l _FSWin,-(sp)
move.l _FSReq,-(sp)
movea.l d2,a0
jsr (a0) ;d0 = (FSReq->dirfunc)(FSReq, FSWin)
addq.w #8,sp
1$
move.l (sp)+,d2
rts
; VOID FSFileFunc(VOID);
; If there is a fsrequest->filefunc, this routine handles the interface.
XDEF _FSFileFunc
_FSFileFunc:
move.l d2,-(sp)
movea.l _FSReq,a0 ;Grab our FSRequest struct
move.l fs_filefunc(a0),d2 ;Is there a user file function to call?
beq.s 1$ ;Nope, that's all we have to do this click!
jsr _ConcatPathString ;Combine dir/file as fullname for return
clr.w _FSDone ;Not done though, undo return status
move.l _FSWin,-(sp)
move.l _FSReq,-(sp)
movea.l d2,a0
jsr (a0) ;d0 = (FSReq->filefunc)(FSReq, FSWin)
addq.w #8,sp
tst.l d0 ;Return 0?
beq.s 1$ ;Yep
move.w #1,_fsvirgindir ;Else re-read directory
1$
move.l (sp)+,d2
rts
; VOID FSSetFileGads(VOID)
; Assign and render currently active file texts, disable remainder
XDEF _FSSetFileGads
_FSSetFileGads:
movem.l d4-d5,-(sp)
move.w _fsnumentries,d5 ;Grab number of entries
beq.s 3$ ;No entries, nothing to set!
; Update visible list based on topfin point in linked list
jsr _FSAssignNodes
; Show all used gadgets
moveq #0,d4 ;i = 0
bra.s 2$
1$
move.l d4,-(sp)
jsr _FSEnableFGad
addq.w #4,sp
addq.w #1,d4 ;Bump gadget count
2$
cmpi.w #10,d4 ;Hit highest gadget?
bcc.s 3$ ;Yep, done
cmp.w d5,d4 ;Else, Hit last gadget?
bcs 1$ ;Nope enable another
3$
movem.l (sp)+,d4-d5
rts
; SetRootDir()
; Chop off all subdirectory names contained in FSPathInfo, moving up to
; root name if possible. Flag to read new directory in any case.
XDEF _SetRootDir
_SetRootDir:
;if ( (tstr = strchr(FSPathInfo.Buffer, ':')) != 0L)
moveq #':',d0
movea.l _FSPathInfo,a0
jsr aindex
tst.l d0
beq.s 1$ ;Nope
clr.b 1(a0) ;Otherwise clobber the char after ':'
move.w #1,_fsvirgindir ;virgindir = 1, read directory
1$ rts
; SetParentDir()
; Chop off last directory name contained in FSPathInfo, moving up one level
; if possible.
XDEF _SetParentDir
_SetParentDir:
movem.l a2-a3,-(sp)
;if (FSPathInfo.Buffer[0])
movea.l _FSPathInfo,a3 ;Grab pointer to path text
tst.b (a3) ;Is it of zero length?
beq.s spddone ;Yep, at root already
;tstr = rindex(FSPathInfo.Buffer, '/')
moveq #'/',d0
movea.l a3,a0
jsr arindex
tst.l d0 ;Grab index to last occurance of slash
bne.s spdnotsub ;If we got one that is
; if ( tstr = rindex(FSPathInfo.Buffer, ':') )
; tstr++;
moveq #':',d0
movea.l a3,a0
jsr arindex ;Grab index to last occurance of colon
tst.l d0
beq.s spdnotroot ;Oops, no colon either, at top of path?
addq.w #1,a0 ;Move past the ':'
bra.s spdnotsub ;Terminate the text
;else
spdnotroot:
movea.l a3,a0 ;tstr = (BYTE *)FSPathInfo.Buffer
spdnotsub:
clr.b (a0) ;*tstr = '\x0'
move.w #1,_fsvirgindir ;virgindir = 1, read the new directory
spddone:
movem.l (sp)+,a2-a3
rts
;HCompGad(rp, g2)
; struct RastPort *rp;
; struct Gadget *g2;
;
; Given a rastport and a gadget pointer, highlight or de-highlight
; a gadget using RectFill in COMPLEMENT mode.
hrp EQU 16
hgad EQU 20
XDEF _HCompGad
_HCompGad:
movem.l d2-d3/a6,-(sp)
movea.l hrp(sp),a1
moveq #2,d0
SYS SetDrMd,_GfxBase ;SetDrMd(rp, COMPLEMENT)
movea.l hgad(sp),a0 ;Grab gadget pointer
moveq #0,d0
move.w 4(a0),d0 ;x0 = (ULONG)g2->LeftEdge
move.l d0,d2
add.w 8(a0),d2
subq.w #1,d2 ;x1 = x0 + g2->Width - 1L
moveq #0,d1
move.w 6(a0),d1 ;y0 = (ULONG)g2->TopEdge
move.l d1,d3
add.w 10(a0),d3
subq.w #1,d3 ;y1 = y0 + g2->Height - 1L
movea.l hrp(sp),a1
SYS RectFill ;RectFill(rp, x0, y0, x1, y1)
movea.l hrp(sp),a1
moveq #1,d0
SYS SetDrMd ;SetDrMd(rp, JAM2)
movem.l (sp)+,d2-d3/a6
rts
;HCompEntry(num)
; LONG num;
;
; Highlight or de-highlight a slot in the filename area, given its
; entry number
XDEF _HCompEntry
_HCompEntry:
movem.l d2-d3/a2/a6,-(sp)
movea.l _FSRPort,a2 ;Grab window
movea.l a2,a1
moveq #2,d0
SYS SetDrMd,_GfxBase ;SetDrMd(rp, COMPLEMENT)
moveq #5,d0 ;x0 = (ULONG)g2->LeftEdge
move.l #460,d2 ;x1 = x0 + g2->Width - 1L
move.w 16+4+2(sp),d1
mulu #11,d1
add.w #12,d1 ;y0 = (ULONG)g2->TopEdge
move.l d1,d3
add.w #9,d3 ;y1 = y0 + g2->Height - 1L
movea.l a2,a1
SYS RectFill ;RectFill(rp, x0, y0, x1, y1)
movea.l a2,a1
moveq #1,d0
SYS SetDrMd ;SetDrMd(rp, JAM2)
movem.l (sp)+,d2-d3/a2/a6
rts
; VOID FSDoSortGadget(type)
; LONG type;
dosgtype EQU 4+4*3
XDEF _FSDoSortGadget
_FSDoSortGadget:
movem.l d2/a2/a6,-(sp)
movea.l _FSReq,a0
moveq #0,d0
move.w fs_sorttype(a0),d0
cmp.w dosgtype+2(sp),d0
beq dosgsame
; Unhighlight previous setting
tst.w d0 ;Alphabetize?
bne.s 1$
lea _AlphaGad,a0
bra.s 3$
1$
subq.w #1,d0 ;FileSize?
bne.s 2$
lea _SizeGad,a0
bra.s 3$
2$
subq.w #1,d0 ;Time?
bne.s 4$ ;Nope, nosort previously
lea _TimeGad,a0
3$
bclr.b #7,gg_Flags+1(a0) ;gad->Flags &= ~SELECTED
movea.l _FSWin,a1
suba.l a2,a2
moveq #1,d0
SYS RefreshGList,_IntuitionBase ;RefreshGList(gad, FSWin, 0L, 1)
4$
; Set new sort type
movea.l _FSReq,a0
move.l dosgtype(sp),d1
move.w d1,fs_sorttype(a0)
movea.l _fnList,a0
movea.l MLH_HEAD(a0),a0
tst.l fn_Node+MLN_SUCC(a0)
beq.s dosgdone ;No list, don't bother sorting
tst.l _topfin ;Grab current topfin
beq.s 5$ ;No currently visible files
clr.w _fsneedshow ;fsneedshow = 0, needs sorting
bra.s 6$
5$
move.w #-1,_fsneedshow ;No topfin, fsneedshow = -1
6$
dossort:
; Sort the list using the new sort type
move.l d1,-(sp)
jsr _SortNodes ;SortNodes(type)
addq.w #4,sp
jsr _FSUpdateSort
jsr _FSWinTitle ;Reset title to previous
bra.s dosgdone
dosgsame:
move.w #-1,fs_sorttype(a0)
dosgdone:
movem.l (sp)+,d2/a2/a6
rts
; SortNodes(key)
; LONG key;
; Selection sort list of filenames using one of three key types
XDEF _SortNodes
_SortNodes:
movem.l d4/a2-a3/a6,-(sp)
IFD BENCHMARK
jsr _StartTime
ENDC
move.l 4+4*4(sp),d4 ;Grab our key type
blt snsortdone ;No sort wanted
cmpi.w #1,_fsnumentries ;More than one entry?
ble snsortdone ;Nope, don't bother sorting
move.w _fstitstatus,-(sp) ;Save old titstatus
move.w #28,_fstitstatus
jsr _FSWinTitle ;FSWinTitle("Sorting...")
move.w (sp)+,_fstitstatus ;Restore previous titlemsg
; Convert Exec list to a simple head->next->NULL type
movea.l _fnList,a3 ;Grab old list
movea.l MLH_TAILPRED(a3),a1 ;a0 = last entry in list
movea.l MLH_HEAD(a3),a0
clr.l fn_Node+MLN_SUCC(a1) ;Zap last nodes next field
NEWLIST a3 ;New the old list
move.l d4,d0 ;d0 = sorttype, a0 = headnode
jsr _FSListSort ;list_sort(headnode, key) (a0/d0)
movea.l d0,a1 ;Grab new head of sorted list
; Now add the new nodes back into the list
movea.l 4,a6 ;Execbase calls
1$ cmpa.l #0,a1 ;Grab next node in new list
beq.s 2$ ;End of list
movea.l fn_Node+MLN_SUCC(a1),a2 ;node = node->fn_Node.mln_Succ
movea.l a3,a0
SYS AddTail ;AddTail(fnList, newnode)
movea.l a2,a1 ;a2 = next node
bra 1$ ;Add the next node
2$
snsortdone:
IFD BENCHMARK
pea _timermsg1
jsr _StopTime
addq.w #4,sp
ENDC
movem.l (sp)+,d4/a2-a3/a6
rts
; struct file_node *FSListSort (list, type)
; struct file_node *list;
; long type;
;
; Assumes a list of structures, with a pointer to "next" as the first
; field. It reorders the list into ascending order, and returns the
; new first node's address. It is order N log(N).
;
; The compare routine should return 0 if the items are in order, and 1
; if they are not. If the compare routine returns 0 in case of
; equality, the sort will be stable.
;
; This routine depends upon compiler-dependant struct layout, but this
; assumption is likely to be fairly commonly valid.
;
; The basic notion of this sort is to make sorted sublists longer and
; longer by merging. On the Nth pass through the list, sorted
; sublists of length 2^(N-1) are produced. Eventually, the entire
; list is sorted, in log2(N)+1 passes through the list. There is
; extra bookkeeping overhead, but minimal extra storage space needed.
; Counts and clever pointer management substitute for extra "glue"
; nodes.
;
; while more than one list
; while not at end of composite lists
; for each merge_length(m) block
; merge first items in lists onto current output list
; toggle current output list
;
; Register parameters:
; struct file_node *FSListSort __ARGS((struct file_node *, LONG));
; d0 a0 d0
flsold1 equ -4
flsold0 equ -8
flsnew1 equ -12
flsnew0 equ -16
flscnt1 equ -20
flscnt0 equ -24
flsffn1 equ flscnt0-16
flsffn0 equ flsffn1-16
flssend equ flsffn0-4
XDEF _FSListSort
_FSListSort:
link a5,#flssend
movem.l d2-d7/a2-a3,-(sp)
move.l d0,d3 ;d3 = sorttype
clr.l flsffn0+LN_SUCC(a5) ;front[0].next = 0
move.l a0,flsffn1+LN_SUCC(a5) ;front[0].next = list
moveq #1,d7 ;m = 1
moveq #0,d6 ;hm = 0
flsLoop1:
tst.l flsffn1+LN_SUCC(a5) ;while (front[1].next)
beq flsdone
lea flsffn0(a5),a0
move.l a0,flsnew0(a5) ;new[0] = &front[0]
lea flsffn1(a5),a0
move.l a0,flsnew1(a5) ;new[1] = &front[1]
move.l flsffn0+LN_SUCC(a5),flsold0(a5) ;old[0] = front[0].next
move.l flsffn1+LN_SUCC(a5),flsold1(a5) ;old[1] = front[1].next
clr.l flscnt0(a5) ;count[0] = 0
clr.l flscnt1(a5) ;count[1] = 0
moveq #0,d4 ;n = 0
moveq #0,d5 ;items_merged = 0
flsLoop2:
tst.l flsold0(a5) ;old[0]?
bne.s 1$ ;Yep, get an item from this list
tst.l flsold1(a5) ;old[1]?
beq flsNext2 ;Nope, both lists exhausted
1$ cmp.l d7,d5 ;if (items_merged >= m)
bcs.s 2$ ;Nope, m > items_merged
moveq #0,d5 ;items_merged = 0
bchg.l #0,d4 ;n = 1 - n
clr.l flscnt0(a5) ;count[0] = 0
clr.l flscnt1(a5) ;count[1] = 0
2$ tst.l flsold0(a5) ;old[0]?
beq.s 3$
tst.l flsold1(a5) ;old[1]?
beq.s 3$
cmp.l flscnt0(a5),d6 ;count[0] < hm?
bls.s 3$ ;Nope, hm >= count[0]
cmp.l flscnt1(a5),d6 ;count[1] < hm?
bls.s 3$ ;Nope
movea.l flsold1(a5),a1
movea.l fn_info(a1),a1
movea.l flsold0(a5),a0
movea.l fn_info(a0),a0
move.l d3,d0
jsr _CompareNodes ;CompareNodes(type, old[0]->info, old[1]->info)
lsl.w #2,d0 ;d0 = result of compare (0 or 1)
move.w d4,d1
lsl.w #2,d1 ;d1 = n<<2
movea.l flsnew0(a5,d1.w),a1 ;a1 = new[n]
movea.l flsold0(a5,d0.w),a0 ;a0 = old[o]
move.l a0,LN_SUCC(a1) ;new[n]->next = old[o]
move.l LN_SUCC(a0),flsold0(a5,d0.w) ;old[o] = old[o]->next
addq.l #1,flscnt0(a5,d0.w) ;count[o]++
bra.s flsNext1
3$
flselse1:
tst.l flsold0(a5) ;old[0]?
beq.s 2$ ;Nope, use old[1]
cmp.l flscnt0(a5),d6 ;count[0] < hm?
bls.s 2$ ;Nope, count[0] >= hm, use old[1]
1$ lea flsold0(a5),a0 ;else a0 = &old[0]
bra.s 3$
2$ lea flsold1(a5),a0 ;a0 = &old[1]
3$
move.w d4,d1
lsl.w #2,d1
movea.l flsnew0(a5,d1.w),a1 ;a1 = new[n]
move.l (a0),LN_SUCC(a1) ;new[n]->next = old[o]
movea.l (a0),a1
move.l LN_SUCC(a1),(a0) ;old[o] = old[o]->next
flsNext1:
move.w d4,d0
lsl.w #2,d0
movea.l flsnew0(a5,d0.w),a0 ;a0 = new[n]
move.l LN_SUCC(a0),flsnew0(a5,d0.w) ;new[n] = new[n]->next
addq.l #1,d5 ;items_merged++
bra flsLoop2
flsNext2:
movea.l flsnew0(a5),a0
clr.l LN_SUCC(a0) ;new[0]->next = 0
movea.l flsnew1(a5),a0
clr.l LN_SUCC(a0) ;new[1]->next = 0
move.l d7,d6 ;hm = m
lsl.l #1,d7 ;m *= 2
bra flsLoop1
flsdone:
move.l flsffn0+LN_SUCC(a5),d0 ;return(front[0].next)
movem.l (sp)+,d2-d7/a2-a3
unlk a5
rts
; d0 = WORD CompareNodes(d0, a0, a1)
; WORD key = d0;
; struct node_data *a = a0, *b = a1;
;
; Compare data in two nodes, based upon key type. Return boolean result
; of the comparison in d0. Note that this is a register based function.
XDEF _CompareNodes
_CompareNodes:
move.w nd_filetype(a0),d1
cmp.w nd_filetype(a1),d1 ;Comparing same type of entries?
beq.s 3$ ;Yep, use sort for compare
btst.b #3,_fsflags+1 ;Want files first?
bne.s 2$ ;Yep
btst.b #4,_fsflags+1 ;Want dirs first?
beq.s 3$ ;Don't care, see if there is a sort
cmp.w nd_filetype(a1),d1 ;Recompare
bcs.s cnmatch ;a0->filetype = 2, a1->filetype = 1
bra.s cnnomatch ;a0->filetype = 1, a1->filetype = 2
2$
cmp.w nd_filetype(a1),d1 ;Recompare
bhi.s cnmatch ;a0->filetype = 2, a1->filetype = 1
bra.s cnnomatch ;a0->filetype = 1, a1->filetype = 2
3$
tst.w d0
blt.s cnmatch ;No sort, append to end
bne.s cnnotalpha ;Not zero, not alphabetize
cnnalpha:
pea nd_alphadata+26(a1)
pea nd_alphadata+26(a0)
jsr _lstrcmp ;return(lstrcmp(a->alphadata + 26L, b->alphadata + 26L) > 0)
addq.w #8,sp
tst.w d0
ble.s cnnomatch
bra.s cnmatch
cnnotalpha:
cmpi.w #1,d0 ;Sort by size?
bne.s cnnotsize ;Nope, must be by date
move.l nd_filesize(a0),d0
cmp.l nd_filesize(a1),d0 ;return(a->filesize > b->filesize)
beq cnnalpha ;Same size, sort alpha
bcs.s cnnomatch ;a1 > a0
bra.s cnmatch
cnnotsize:
move.l nd_days(a0),d0
cmp.l nd_days(a1),d0 ;if (a->days > b->days)
beq.s cntstmins ;Nope, a->days == b->days, check minutes
bls.s cnnomatch ;Nope, a->days < b->days
bra.s cnmatch
cntstmins:
;t1 = (a->minutes - b->minutes) * 3000L + (a->ticks - b->ticks)
move.l nd_minutes(a0),d0
sub.l nd_minutes(a1),d0
muls #3000,d0
move.l nd_ticks(a0),d1
sub.l nd_ticks(a1),d1
add.l d1,d0
tst.l d0 ;return(t1 > 0L);
beq cnnalpha ;Same date, sort alpha
bgt.s cnmatch
cnnomatch:
moveq #0,d0
bra.s cndone
cnmatch:
moveq #1,d0
cndone:
rts
; LONG lstrcmp(astr, bstr)
; BYTE *astr, *bstr;
;
; Compare two texts for lexigraphic order, ignoring case differences
XDEF _lstrcmp
_lstrcmp:
movem.l 4(sp),a0/a1 ;Grab astr, bstr
;for(;*a && tolower(*a) == tolower(*b); a++, b++)
lccstart:
move.b (a0)+,d0 ;Grab a char from astr
cmpi.b #$40,d0 ;less than @ character?
bls.s 1$ ;Yep
cmpi.b #$5a,d0 ;Greater than Z?
bhi.s 1$ ;Yep
addi.b #$20,d0
1$
move.b (a1)+,d1 ;Grab a char from bstr
cmpi.b #$40,d1 ;less than @ character?
bls.s 2$ ;Yep
cmpi.b #$5a,d1 ;Greater than Z?
bhi.s 2$ ;Yep
addi.b #$20,d1
2$
tst.b d0 ;End of astr?
beq.s 3$
cmp.b d1,d0 ;Are they the same character?
beq lccstart ;Yep, compare next pair of chars
3$
sub.b d1,d0 ;return(tolower(*astr) - tolower(*bstr))
ext.w d0
ext.l d0
rts
; Search a text for wild characters, return 1 if found
XDEF _iswild
_iswild:
movea.l 4(sp),a0 ;Grab text pointer
moveq #0,d0 ;Clear out our character register
ischk1:
move.b (a0)+,d0 ;Grab a char
beq.s iswdone ;Might be end of text?
cmpi.b #'*',d0 ;Is it *?
beq.s iswdone ;yep, is wild
cmpi.b #'?',d0 ;Is it a qmark
bne ischk1 ;Nope, check next character
rts ;Otherwise it is wild
iswdone:
rts
; Compare a wild card name with a normal name
; WORD wildmatch (name, wild)
; BYTE *name, *wild;
XDEF _wildmatch
_wildmatch:
link a5,#-64
movem.l d3/a2-a3,-(sp)
movem.l 8(a5),a2-a3 ;Grab name/pattern
lea -64(a5),a0 ;back[0][0]
lea -60(a5),a1 ;back[0][1]
moveq #0,d3 ;bi = 0
wmloop1:
tst.b (a2) ;End of name?
bne.s wmnoteon
tst.b (a3) ;End of pattern?
beq wmmatched ;Yep, we matched
wmnoteon:
cmpi.b #'*',(a3) ;Is it a splat?
bne.s wmnotstar ;Nope, maybe '?'
cmpi.w #64,d3 ;Have we hit max expression depth?
beq wmnomatch ;Yep, ran out of room in recursion table
;back[bi][0] = w
move.l a3,0(a0,d3.w) ;Stash pointer to this '*' in table
;back[bi][1] = n
move.l a2,0(a1,d3.w)
addq.w #8,d3 ;++bi
addq.w #1,a3 ;++w
bra wmloop1 ;Check next
wmgoback:
subq.w #8,d3 ;--bi
move.l a0,d0
wmback1:
tst.w d3 ;while (bi >= 0 && *back[bi][1] == '\x0')
blt.s wmbacked
movea.l 0(a1,d3.l),a0
tst.b (a0)
bne.s wmbacked
subq.w #8,d3 ;--bi
bra wmback1
wmbacked:
tst.w d3 ;if (bi < 0)
blt.s wmnomatch ;return (0)
movea.l d0,a0
movea.l 0(a0,d3.w),a3 ;w = back[bi][0] + 1
addq.w #1,a3
addq.l #1,0(a1,d3.w)
movea.l 0(a1,d3.l),a2 ;n = ++back[bi][1]
addq.w #8,d3 ;++bi
bra wmloop1
wmnotstar:
cmpi.b #'?',(a3) ;Is it '?'
bne.s wmnotqmark
tst.b (a2) ;Reached end of text?
bne.s wmincpoint ;Nope, move on to next char
tst.w d3 ;Are we at top level of expression?
beq.s wmnomatch ;Yep, expression didn't match
bra wmgoback ;Otherwise pop a level and try to match
wmnotqmark:
move.b (a2),d0 ;Grab a char from bstr
cmpi.b #$40,d0 ;less than @ character?
bls.s 1$ ;Yep
cmpi.b #$5a,d0 ;Greater than Z?
bhi.s 1$ ;Yep
addi.b #$20,d0
1$
move.b (a3),d1 ;Grab a char from bstr
cmpi.b #$40,d1 ;less than @ character?
bls.s 2$ ;Yep
cmpi.b #$5a,d1 ;Greater than Z?
bhi.s 2$ ;Yep
addi.b #$20,d1
2$
cmp.b d0,d1 ;*n = *w?
beq.s wmincpoint ;Yep, move on past
tst.w d3 ;Are we at top expression level?
beq.s wmnomatch ;Yep, they didn't match
bra wmgoback ;Nope, process next part
wmincpoint:
tst.b (a2) ;Done with name?
beq.s wmnamend ;Yep
addq.w #1,a2 ;Otherwise increment name pointer
wmnamend:
tst.b (a3) ;End of pattern?
beq.s wmmatched ;Yep, we matched
addq.w #1,a3 ;Otherwise inc wild pointer, match next char
bra wmloop1
wmmatched:
moveq #1,d0
bra.s wmdone
wmnomatch:
moveq #0,d0
wmdone:
movem.l (sp)+,d3/a2-a3
unlk a5
rts
; LONG MakePathString(lock, dest)
; a0 a1
; struct FileLock *lock;
; BYTE *dest;
;
; DESCRIPTION:
; Given text and a filelock, construct entire pathname and
; return in dest.
XDEF _MakePathString
_MakePathString:
link a5,#0
movem.l d2-d5/d7/a2-a3/a6,-(sp)
; Grab pointer to lock and dest text to fill
move.l 8(a5),d3 ;d3 = lock
movea.l 12(a5),a2 ;a2 = dest
clr.b (a2) ;NULL terminate dest
moveq #0,d5 ;LockFlag = 0
; Allocate a FileInfoBlock for local use
moveq #0,d1
move.l #fib_SIZEOF,d0
SYS AllocMem,4 ;AllocMem(sizeof(fib), 0L)
move.l d0,d7 ;d7 = *fib
beq mpsfailed ;Whoops no mem? return!
movea.l _DOSBase(a4),a6 ;DOSBase calls from here on
; while (lock != 0)
1$
tst.l d3 ;Got a lock?
beq.s mpsokay ;Nope, must be at root
; Examine the current lock
move.l d3,d1
move.l d7,d2
SYS Examine ;Examine(lock, fib)
tst.l d0 ;Okay?
beq.s mpsfailed ;Nope, some sort of dos failure?
movea.l d7,a1
cmpi.b #' ',fib_FileName(a1) ;if (fib->fib_FileName[0] >= ' ')
bcs.s 3$ ;Nope, don't bother inserting?
tst.b (a2) ;if (dest[0] != 0)
beq.s 2$
lea _SlashStr(a4),a1
movea.l a2,a0
jsr _InsertPathString ;InsertPathString(dest, "/");
2$
movea.l d7,a1
lea fib_FileName(a1),a1
movea.l a2,a0
jsr _InsertPathString ;InsertPathString(dest, fib->fib_FileName)
3$
; Okay, move up one directory
move.l d3,d4 ;oldlock = lock
move.l d3,d1
SYS ParentDir
move.l d0,d3 ;lock = ParentDir(lock)
tst.w d5 ;LockFlag set?
bne.s 4$ ;Yep, unlock
moveq #1,d5 ;Else LockFlag = 1, unlock next time
bra 1$ ;Next directory up
4$
move.l d4,d1
SYS UnLock ;UnLock(oldlock)
bra 1$ ;Examine
mpsokay:
; See if root was RAM:, special case
movea.l d7,a1 ;a1 = fib
cmpi.b #' ',fib_FileName(a1) ;if (fib->fib_FileName[0] >= ' ')
bcc.s 1$ ;Yep, not 1.1/1.2 RAM:
lea _RamDirNameStr(a4),a1 ;Else...
movea.l a2,a0
jsr _InsertPathString ;InsertPathString(dest, "RAM:")
bra.s mpsdone
1$
; Find last slash we tacked on, change to a colon, or, add a colon
moveq #'/',d0
movea.l a2,a0
jsr aindex ;d0 = strchr(dest, '/')
tst.l d0 ;Do we have a slash?
beq.s 2$ ;Nope, at root....
movea.l d0,a0
move.b #':',(a0) ;Else change first '/' to a ':'
bra.s mpsdone
; No slash, must be locked at the root. Append a colon to the dest.
2$
lea _ColonStr(a4),a1
movea.l a2,a0
jsr astrcat ;strcat (dest, ":")
bra.s mpsdone
; Come here if an error occured, return empty text to caller
mpsfailed:
clr.b (a2) ;dest[0] = (BYTE)0
moveq #0,d3 ;return (0L)
bra.s mpsdeall
; Come here if everything is okay, deallocate FileInfoBlock
mpsdone:
moveq #1,d3 ;return (1L)
mpsdeall:
tst.l d7 ;Did we allocate a fib?
beq.s mpsfinis ;nope
movea.l d7,a1 ;Else free the memory
move.l #fib_SIZEOF,d0
SYS FreeMem ;FreeMem(fib, sizeof(fib))
mpsfinis:
move.l d3,d0 ;Put return value in d0
movem.l (sp)+,d2-d5/d7/a2-a3/a6
unlk a5
rts
; VOID InsertPathString(dest, source)
; a0 a1
; BYTE *dest, *source;
;
; DESCRIPTION:
; Insert source text into dest text.
; Special case for source length == 0, source must be RAM.
XDEF _InsertPathString
_InsertPathString:
movem.l d7/a2-a3,-(sp)
movea.l a1,a3 ;a3 = source
move.l a0,a2 ;a2 = dest
movea.l a3,a0
jsr astrlen
move.l d0,d7 ;d7 = strlen(source)
1$ movea.l a2,a0
jsr astrlen ;d0 = strlen(dest)
addq.w #1,d0 ;Bump the length to include zero byte at end
movea.l a2,a1
adda.w d7,a1 ;Push dest + slen
movea.l a2,a0 ;Push dest
jsr amovmem ;amovmem(dest, dest + slen, strlen(dest) + 1)
move.w d7,d0
movea.l a2,a1
movea.l a3,a0
jsr amovmem ;amovmem(source, dest, slen)
movem.l (sp)+,d7/a2-a3
rts
; BYTE *myrindex(text, searchchar)
; BYTE *text;
; LONG searchchar;
;
; C stack version of arindex.
XDEF _myrindex
_myrindex:
movea.l 4(sp),a0
move.l 8(sp),d0
; BYTE *aindex(BYTE *, BYTE);
XDEF aindex
aindex:
1$ cmp.b (a0),d0
beq.s aifound
tst.b (a0)+
beq.s ainomatch
bra 1$
ainomatch:
moveq #0,d0
rts
aifound:
move.l a0,d0
rts
; BYTE *arindex(BYTE *, BYTE);
XDEF arindex
arindex:
move.l a0,d1 ;Copy start of string for compares
1$ tst.b (a0)+ ;Find end of text
bne 1$
2$ cmp.b -(a0),d0 ;Now work backward comparing along the way
beq.s rifound ;..Until we find a match
cmpa.l d1,a0 ;...or hit the beginning of the text
bgt 2$
rinomatch:
moveq #0,d0
rts
rifound:
move.l a0,d0
rts
; d0 a0
; LONG astrlen(text)
; BYTE *text;
;
; Synopsis: Calculate length of null-byte terminated text.
; a0 returns pointing to null char at end of text
; d0 returns number of bytes in the text
XDEF astrlen
astrlen:
move.l a0,d0 ;Save initial address
1$ tst.b (a0)+ ;Test a byte for zero-ness
bne 1$
suba.l d0,a0 ;Minus initial address
subq.w #1,a0 ;Less one for overshoot
exg d0,a0 ;swap em
rts
; astrcat()
; Takes text in a0, appends text in a1
; a0 returns pointing to null at end of final text
XDEF astrcat
astrcat:
; Find end of first text
1$ tst.b (a0)+
bne 1$
subq.w #1,a0 ;Back up to null char
; Append second text
2$ move.b (a1)+,(a0)+
bne 2$
subq.w #1,a0 ;a0 = the null at end of final text
rts
; astrcpy()
; Takes text in a0, copies text in a1
; a0 returns pointing to null at end of final text
XDEF astrcpy
astrcpy:
; Copy second text
1$ move.b (a1)+,(a0)+
bne 1$
subq.w #1,a0 ;Back up to null
rts
; astrcmp()
; Takes text in a0, compares to text in a1
; a0 returns pointing to first difference, d0 contains the difference
; or zero if the two texts are identical
XDEF astrcmp
astrcmp:
1$ move.b (a0)+,d0 ;Grab a char from A
move.b (a1)+,d1 ;Grab a char from B
tst.b d0 ;Hit end of A?
beq.s 2$ ;Yep, diff em
cmp.b d1,d0 ;Else the same char?
beq 1$ ;Compare next pair
2$ sub.b d1,d0 ;A - B
ext.w d0
ext.l d0
rts
; safestrcpy(dest, source, length)
; Copies at most length chars of source to dest, if source < length
; don't pad with nulls like strncpy. Always null terminates dest.
XDEF _safestrcpy
_safestrcpy:
movem.l 4(sp),a0/a1 ;Grab dest and source pointers
move.w 14(sp),d0 ;Grab count
; astrncpy()
; Takes text in a1, copies d0 bytes to text in a0.
; a0 returns pointing to null at end of final text.
; Dest text is always null terminated.
XDEF astrncpy
astrncpy:
1$ move.b (a1)+,(a0)+
2$ dbeq d0,1$
subq.w #1,a0
clr.b (a0) ;Null terminate dest
move.l a0,d0
rts
; amovmem()
; Takes text in a0, copies d0 bytes to text in a1. Correctly handles
; overlapping memory.
XDEF amovmem
amovmem:
cmpa.l a0,a1 ;Low to high or high to low?
bcs.s 2$ ;High to low, copy forward
adda.w d0,a0 ;Else start at end, copy backward
adda.w d0,a1
1$ move.b -(a0),-(a1)
subq.w #1,d0
bgt 1$
bra.s amdone
2$ move.b (a0)+,(a1)+
subq.w #1,d0
bgt 2$
amdone:
rts
END
#endasm
#endif /* PATHMASTER */